message.c revision 0c27b3fe77ac1d5094ba3521e8142d9e7973133f
/*
* Copyright (C) 1999-2016 Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*! \file */
/***
*** Imports
***/
#include <config.h>
#include <ctype.h>
#include <dns/keyvalues.h>
#include <dns/masterdump.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#ifdef SKAN_MSG_DEBUG
static void
unsigned char *p;
unsigned int cnt;
p = base;
cnt = 0;
if (cnt % 16 == 0)
printf("%p: ", p);
else if (cnt % 8 == 0)
printf(" |");
p++;
cnt++;
if (cnt % 16 == 0)
printf("\n");
}
if (cnt % 16 != 0)
printf("\n");
}
#endif
#define DNS_MESSAGE_OPCODE_MASK 0x7800U
#define DNS_MESSAGE_OPCODE_SHIFT 11
#define DNS_MESSAGE_RCODE_MASK 0x000fU
#define DNS_MESSAGE_FLAG_MASK 0x8ff0U
#define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U
#define DNS_MESSAGE_EDNSRCODE_SHIFT 24
#define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U
#define DNS_MESSAGE_EDNSVERSION_SHIFT 16
#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))
#define ADD_STRING(b, s) {if (strlen(s) >= \
return(ISC_R_NOSPACE); else \
isc_buffer_putstr(b, s);}
#define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
&& ((s) < DNS_PSEUDOSECTION_MAX))
/*%
* This is the size of each individual scratchpad buffer, and the numbers
* of various block allocations used within the server.
* XXXMLG These should come from a config setting.
*/
#define SCRATCHPAD_SIZE 512
#define NAME_COUNT 8
#define OFFSET_COUNT 4
#define RDATA_COUNT 8
#define RDATALIST_COUNT 8
#define RDATASET_COUNT RDATALIST_COUNT
/*%
* Text representation of the different items, for message_totext
* functions.
*/
static const char *sectiontext[] = {
"QUESTION",
"ANSWER",
"AUTHORITY",
"ADDITIONAL"
};
static const char *updsectiontext[] = {
"ZONE",
"PREREQUISITE",
"UPDATE",
"ADDITIONAL"
};
static const char *opcodetext[] = {
"QUERY",
"IQUERY",
"STATUS",
"RESERVED3",
"NOTIFY",
"UPDATE",
"RESERVED6",
"RESERVED7",
"RESERVED8",
"RESERVED9",
"RESERVED10",
"RESERVED11",
"RESERVED12",
"RESERVED13",
"RESERVED14",
"RESERVED15"
};
/*%
* "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 aligned correctly.
*/
struct dns_msgblock {
unsigned int count;
unsigned int remaining;
}; /* dynamically sized */
static inline dns_msgblock_t *
msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
static inline void *
msgblock_internalget(dns_msgblock_t *, unsigned int);
static inline void
static inline void
static void
/*
* 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
{
unsigned int length;
}
/*
* 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 isc_result_t
if (result != ISC_R_SUCCESS)
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
static inline isc_buffer_t *
return (dynbuf);
}
static inline void
}
static inline dns_rdata_t *
return (rdata);
}
return (NULL);
}
return (rdata);
}
static inline void
}
static inline dns_rdatalist_t *
goto out;
}
sizeof(dns_rdatalist_t),
return (NULL);
}
out:
return (rdatalist);
}
static inline dns_offsets_t *
sizeof(dns_offsets_t),
return (NULL);
}
return (offsets);
}
static inline void
msginitheader(dns_message_t *m) {
m->id = 0;
m->flags = 0;
m->rcode = 0;
m->opcode = 0;
m->rdclass = 0;
}
static inline void
msginitprivate(dns_message_t *m) {
unsigned int i;
for (i = 0; i < DNS_SECTION_MAX; i++) {
m->counts[i] = 0;
}
m->opt_reserved = 0;
m->sig_reserved = 0;
m->reserved = 0;
}
static inline void
msginittsig(dns_message_t *m) {
m->tsigstatus = dns_rcode_noerror;
m->sigstart = -1;
m->sig0status = dns_rcode_noerror;
m->timeadjust = 0;
}
/*
* Init elements to default state. Used both when allocating a new element
* and when resetting one.
*/
static inline void
msginit(dns_message_t *m) {
msginitheader(m);
msginitprivate(m);
msginittsig(m);
m->header_ok = 0;
m->question_ok = 0;
m->tcp_continuation = 0;
m->verified_sig = 0;
m->verify_attempted = 0;
m->free_query = 0;
m->free_saved = 0;
m->cc_ok = 0;
m->cc_bad = 0;
m->tkey = 0;
m->rdclass_set = 0;
}
static inline void
unsigned int i;
/*
* Clean up name lists by calling the rdataset disassociate function.
*/
for (i = first_section; i < DNS_SECTION_MAX; i++) {
}
if (dns_name_dynamic(name))
}
}
}
static void
{
if (msg->opt_reserved > 0) {
msg->opt_reserved = 0;
}
}
}
static void
if (msg->sig_reserved > 0) {
msg->sig_reserved = 0;
}
if (replying) {
} else {
}
}
}
}
}
}
/*
* Free all but one (or everything) for this message. This is used by
* both dns_message_reset() and dns_message_destroy().
*/
static void
msgresetnames(msg, 0);
/*
* Clean up linked lists.
*/
/*
* Run through the free lists, and just unlink anything found there.
* The memory isn't lost since these are part of message blocks we
* have allocated.
*/
}
}
if (!everything) {
}
}
}
}
/*
* rdatalists could be empty.
*/
}
}
}
}
}
if (msg->free_query != 0)
}
if (msg->free_saved != 0)
}
/*
* cleanup the buffer cleanup list
*/
}
/*
* Set other bits to normal default values.
*/
if (!everything)
}
static unsigned int
unsigned int x;
/*
* The space required for an TSIG record is:
*
* n1 bytes for the name
* 2 bytes for the type
* 2 bytes for the class
* 4 bytes for the ttl
* 2 bytes for the rdlength
* n2 bytes for the algorithm name
* 6 bytes for the time signed
* 2 bytes for the fudge
* 2 bytes for the MAC size
* x bytes for the MAC
* 2 bytes for the original id
* 2 bytes for the error
* 2 bytes for the other data length
* y bytes for the other data (at most)
* ---------------------------------
* 26 + n1 + n2 + x + y bytes
*/
x = 0;
else {
if (result != ISC_R_SUCCESS)
x = 0;
}
}
{
dns_message_t *m;
unsigned int i;
|| intent == DNS_MESSAGE_INTENTRENDER);
if (m == NULL)
return (ISC_R_NOMEMORY);
/*
* No allocations until further notice. Just initialize all lists
* and other members that are freed in the cleanup phase here.
*/
m->magic = DNS_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->cleanup);
ISC_LIST_INIT(m->rdatas);
ISC_LIST_INIT(m->rdatalists);
ISC_LIST_INIT(m->offsets);
ISC_LIST_INIT(m->freerdata);
/*
* Ok, it is safe to allocate (and then "goto cleanup" if failure)
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
&m->rdspool);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
*msgp = m;
return (ISC_R_SUCCESS);
/*
* Cleanup for error returns.
*/
}
isc_mempool_destroy(&m->namepool);
isc_mempool_destroy(&m->rdspool);
m->magic = 0;
return (ISC_R_NOMEMORY);
}
void
|| intent == DNS_MESSAGE_INTENTRENDER);
}
void
}
static isc_result_t
{
return (ISC_R_SUCCESS);
}
}
return (ISC_R_NOTFOUND);
}
{
return (ISC_R_SUCCESS);
}
}
return (ISC_R_NOTFOUND);
}
{
return (ISC_R_SUCCESS);
}
}
return (ISC_R_NOTFOUND);
}
/*
* Read a name from buffer "source".
*/
static isc_result_t
{
unsigned int tries;
/*
* First try: use current buffer.
* Second try: allocate a new buffer and use that.
*/
tries = 0;
while (tries < 2) {
scratch);
if (result == ISC_R_NOSPACE) {
tries++;
if (result != ISC_R_SUCCESS)
return (result);
} else {
return (result);
}
}
INSIST(0); /* Cannot get here... */
return (ISC_R_UNEXPECTED);
}
static isc_result_t
{
unsigned int tries;
unsigned int trysize;
/*
* First try: use current buffer.
* Second try: allocate a new buffer of size
* max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
* (the data will fit if it was not more than 50% compressed)
* Subsequent tries: double buffer size on each try.
*/
tries = 0;
trysize = 0;
/* XXX possibly change this to a while (tries < 2) loop */
for (;;) {
scratch);
if (result == ISC_R_NOSPACE) {
if (tries == 0) {
if (trysize < SCRATCHPAD_SIZE)
} else {
if (trysize >= 65535)
return (ISC_R_NOSPACE);
/* XXX DNS_R_RRTOOLONG? */
trysize *= 2;
}
tries++;
if (result != ISC_R_SUCCESS)
return (result);
} else {
return (result);
}
}
}
#define DO_ERROR(r) \
do { \
if (best_effort) \
seen_problem = ISC_TRUE; \
else { \
result = r; \
goto cleanup; \
} \
} while (0)
static isc_result_t
unsigned int options)
{
isc_region_t r;
unsigned int count;
return (ISC_R_NOMEMORY);
goto cleanup;
}
/*
* Parse the name out of this packet.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* 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 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
* 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 != ISC_R_SUCCESS) {
if (!ISC_LIST_EMPTY(*section))
} else {
}
/*
* Get type and class.
*/
if (r.length < 4) {
goto cleanup;
}
/*
* If this class is different than the one we already read,
* this is an error.
*/
if (msg->rdclass_set == 0) {
/*
* Is this a TKEY query?
*/
if (rdtype == dns_rdatatype_tkey)
/*
* Can't ask the same question twice.
*/
if (result == ISC_R_SUCCESS)
/*
* Allocate a new rdatalist.
*/
goto cleanup;
}
goto cleanup;
}
/*
* Convert rdatalist to rdataset, and attach the latter to
* the name.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
}
if (seen_problem)
return (DNS_R_RECOVERABLE);
return (ISC_R_SUCCESS);
}
#if 0
#endif
if (free_name)
return (result);
}
static isc_boolean_t
if (section == DNS_SECTION_PREREQUISITE)
rdclass == dns_rdataclass_none));
if (section == DNS_SECTION_UPDATE)
return (ISC_FALSE);
}
static isc_result_t
{
isc_region_t r;
return (ISC_R_NOMEMORY);
goto cleanup;
}
/*
* Parse the name out of this packet.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* Get type, class, ttl, and rdatalen. Verify that at least
* rdatalen bytes remain. (Some of this is deferred to
* later.)
*/
goto cleanup;
}
/*
* If there was no question section, we may not yet have
* established a class. Do so now.
*/
if (msg->rdclass_set == 0 &&
}
/*
* If this class is different than the one in the question
* section, bail.
*/
&& rdtype != dns_rdatatype_tsig
&& rdtype != dns_rdatatype_opt
/*
* record's class needs to match.
*/
rdtype == dns_rdatatype_key &&
/*
* Special type handling for TSIG, OPT, and TKEY.
*/
if (rdtype == dns_rdatatype_tsig) {
/*
* If it is a tsig, verify that it is in the
* additional data section.
*/
if (sectionid != DNS_SECTION_ADDITIONAL ||
rdclass != dns_rdataclass_any ||
} else if (rdtype == dns_rdatatype_opt) {
/*
* The name of an OPT record must be ".", it
* must be in the additional data section, and
* it must be the first OPT we've seen.
*/
} else if (rdtype == dns_rdatatype_tkey) {
/*
* A TKEY must be in the additional section if this
* is a query, and the answer section if this is a
* response. Unless it's a Win2000 client.
*
* Its class is ignored.
*/
else
if (sectionid != tkeysection &&
}
/*
* ... now get ttl and rdatalen, and check buffer.
*/
goto cleanup;
}
/*
* Read the rdata from the wire format. Interpret the
* rdata according to its actual class, even if it had a
* DynDNS meta-class in the packet (unless this is a TSIG).
* Then put the meta-class back into the finished rdata.
*/
goto cleanup;
}
if (rdatalen != 0) {
goto cleanup;
}
/*
* When the rdata is empty, the data pointer is
* never dereferenced, but it must still be non-NULL.
* Casting 1 rather than "" avoids warnings about
* discarding the const attribute of a string,
* for compilers that would warn about such things.
*/
} else if (rdclass == dns_rdataclass_none &&
sectionid == DNS_SECTION_UPDATE) {
} else
if (result != ISC_R_SUCCESS)
goto cleanup;
if (rdtype == dns_rdatatype_rrsig &&
if (covers == 0)
if (covers == 0) {
if (sectionid != DNS_SECTION_ADDITIONAL ||
} else {
}
} else
covers = 0;
/*
* Check the ownername of NSEC3 records
*/
if (rdtype == dns_rdatatype_nsec3 &&
ISC_FALSE)) {
goto cleanup;
}
/*
* If we are doing a dynamic update or this is a meta-type,
* don't bother searching for a name, just append this one
* to the end of the message.
*/
if (rdtype != dns_rdatatype_opt &&
rdtype != dns_rdatatype_tsig &&
{
}
} 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.
*/
/*
* If it is a new name, append to the section.
*/
if (result == ISC_R_SUCCESS) {
} else {
}
}
/*
* Search name for the particular type and class.
* Skip this stage if in update mode or this is a meta-type.
*/
else {
/*
* If this is a type that can only occur in
* the question section, fail.
*/
}
/*
* 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. When appending, make certain that the type isn't
* a singleton type, such as SOA or CNAME.
*
* Note that this check will be bypassed when preserving order,
* the opcode is an update, or the type search is skipped.
*/
if (result == ISC_R_SUCCESS) {
if (dns_rdatatype_issingleton(rdtype)) {
&rdatalist);
}
}
if (result == ISC_R_NOTFOUND) {
goto cleanup;
}
goto cleanup;
}
== ISC_R_SUCCESS);
if (rdtype != dns_rdatatype_opt &&
rdtype != dns_rdatatype_tsig &&
{
}
}
/*
* Minimize TTLs.
*
* Section 5.2 of RFC2181 says we should drop
* nonauthoritative rrsets where the TTLs differ, but we
* currently treat them the as if they were authoritative and
* minimize them.
*/
}
/* Append this rdata to the rdataset. */
/*
* If this is an OPT, SIG(0) or TSIG record, remember it.
* Also, set the extended rcode for TSIG.
*
* Note msg->opt, msg->sig0 and msg->tsig will only be
* already set if best-effort parsing is enabled otherwise
* there will only be at most one of each.
*/
ercode = (dns_rcode_t)
>> 20);
/* Windows doesn't like TSIG names to be compressed. */
}
if (seen_problem) {
if (free_name)
if (free_rdataset)
}
}
if (seen_problem)
return (DNS_R_RECOVERABLE);
return (ISC_R_SUCCESS);
if (free_name)
if (free_rdataset)
return (result);
}
unsigned int options)
{
isc_region_t r;
origsource = *source;
msg->question_ok = 0;
if (r.length < DNS_MESSAGE_HEADERLEN)
return (ISC_R_UNEXPECTEDEND);
/*
* -1 means no EDNS.
*/
goto truncated;
if (ret == DNS_R_RECOVERABLE) {
ret = ISC_R_SUCCESS;
}
if (ret != ISC_R_SUCCESS)
return (ret);
goto truncated;
if (ret == DNS_R_RECOVERABLE) {
ret = ISC_R_SUCCESS;
}
if (ret != ISC_R_SUCCESS)
return (ret);
goto truncated;
if (ret == DNS_R_RECOVERABLE) {
ret = ISC_R_SUCCESS;
}
if (ret != ISC_R_SUCCESS)
return (ret);
goto truncated;
if (ret == DNS_R_RECOVERABLE) {
ret = ISC_R_SUCCESS;
}
if (ret != ISC_R_SUCCESS)
return (ret);
if (r.length != 0) {
"message has %u byte(s) of trailing garbage",
r.length);
}
if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
else {
return (ISC_R_NOMEMORY);
}
return (DNS_R_RECOVERABLE);
if (seen_problem == ISC_TRUE)
return (DNS_R_RECOVERABLE);
return (ISC_R_SUCCESS);
}
{
isc_region_t r;
/*
* Erase the contents of this buffer.
*/
/*
* Make certain there is enough for at least the header in this
* buffer.
*/
if (r.length < DNS_MESSAGE_HEADERLEN)
return (ISC_R_NOSPACE);
return (ISC_R_NOSPACE);
/*
* Reserve enough space for the header in this buffer.
*/
return (ISC_R_SUCCESS);
}
isc_region_t r, rn;
/*
* Ensure that the new buffer is empty, and has enough space to
* hold the current contents.
*/
/*
* Copy the contents from the old to the new buffer.
*/
return (ISC_R_SUCCESS);
}
void
}
isc_region_t r;
return (ISC_R_NOSPACE);
}
return (ISC_R_SUCCESS);
}
static inline isc_boolean_t
int pass_needed;
/*
* If we are not rendering class IN, this ordering is bogus.
*/
return (ISC_FALSE);
case dns_rdatatype_a:
case dns_rdatatype_aaaa:
pass_needed = 4;
else
pass_needed = 3;
break;
case dns_rdatatype_rrsig:
case dns_rdatatype_dnskey:
pass_needed = 2;
break;
default:
pass_needed = 1;
}
if (pass_needed >= pass)
return (ISC_FALSE);
return (ISC_TRUE);
}
#ifdef ALLOW_FILTER_AAAA
/*
* Decide whether to not answer with an AAAA record and its RRSIG
*/
static inline isc_boolean_t
{
if (sectionid == DNS_SECTION_QUESTION)
return (ISC_FALSE);
case dns_rdatatype_ns:
if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
return (ISC_FALSE);
break;
case dns_rdatatype_aaaa:
if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
return (ISC_FALSE);
break;
case dns_rdatatype_rrsig:
if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
return (ISC_FALSE);
return (ISC_FALSE);
break;
default:
return (ISC_FALSE);
}
return (ISC_FALSE);
return (ISC_TRUE);
}
#endif
unsigned int options)
{
int pass;
unsigned int rd_options;
if ((sectionid == DNS_SECTION_ADDITIONAL)
&& (options & DNS_MESSAGERENDER_ORDERED) == 0) {
if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
pass = 4;
} else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
pass = 4;
} else
pass = 3;
} else
pass = 1;
if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
rd_options = 0;
else
/*
* Shrink the space in the buffer by the reserved amount.
*/
total = 0;
/*
* Render required glue first. Set TC if it won't fit.
*/
count = 0;
if (partial)
name,
&count,
NULL);
else
name,
&count);
return (result);
}
if (result == ISC_R_NOSPACE)
if (result != ISC_R_SUCCESS) {
return (result);
}
}
}
do {
return (ISC_R_SUCCESS);
}
if ((rdataset->attributes &
DNS_RDATASETATTR_RENDERED) != 0)
goto next;
if (((options & DNS_MESSAGERENDER_ORDERED)
== 0)
&& (sectionid == DNS_SECTION_ADDITIONAL)
goto next;
#ifdef ALLOW_FILTER_AAAA
/*
* Suppress AAAAs if asked and we are
* not doing DNSSEC or are breaking DNSSEC.
* Say so in the AD bit if we break DNSSEC.
*/
if (sectionid == DNS_SECTION_ANSWER ||
goto next;
}
#endif
count = 0;
if (partial)
name,
&count,
NULL);
else
name,
&count);
/*
* If out of space, record stats on what we
* rendered so far, and return that status.
*
* XXXMLG Need to change this when
* dns_rdataset_towire() can render partial
* sets starting at some arbitrary point in the
* set. This will include setting a bit in the
* rdataset to indicate that a partial
* rendering was done, and some state saved
* somewhere (probably in the message struct)
* to indicate where to continue from.
*/
return (result);
}
if (result != ISC_R_SUCCESS) {
return (result);
}
/*
* If we have rendered non-validated data,
* ensure that the AD bit is not set.
*/
(sectionid == DNS_SECTION_ANSWER ||
rdataset->attributes |=
next:
}
}
} while (--pass != 0);
return (ISC_R_SUCCESS);
}
void
isc_region_t r;
}
isc_region_t r;
int result;
unsigned int count;
/*
* We have an extended rcode but are not using EDNS.
*/
return (DNS_R_FORMERR);
}
/*
* If we're adding a OPT, TSIG or SIG(0) to a truncated message,
* clear all rdatasets from the message except for the question
* before adding the OPT, TSIG or SIG(0). If the question doesn't
* fit, don't include it.
*/
{
0);
return (result);
}
/*
* If we've got an OPT record, render it.
*/
msg->opt_reserved = 0;
/*
* Set the extended rcode.
*/
/*
* Render.
*/
count = 0;
&count);
if (result != ISC_R_SUCCESS)
return (result);
}
/*
* If we're adding a TSIG record, generate and render it.
*/
msg->sig_reserved = 0;
if (result != ISC_R_SUCCESS)
return (result);
count = 0;
&count);
if (result != ISC_R_SUCCESS)
return (result);
}
/*
* If we're adding a SIG(0) record, generate and render it.
*/
msg->sig_reserved = 0;
if (result != ISC_R_SUCCESS)
return (result);
count = 0;
/*
* Note: dns_rootname is used here, not msg->sig0name, since
* the owner name of a SIG(0) is irrelevant, and will not
* be set in a message being rendered.
*/
&count);
if (result != ISC_R_SUCCESS)
return (result);
}
return (ISC_R_SUCCESS);
}
void
unsigned int i;
/*
* Reset the message so that it may be rendered again.
*/
for (i = 0; i < DNS_SECTION_MAX; i++) {
}
}
}
}
}
}
return (ISC_R_NOMORE);
return (ISC_R_SUCCESS);
}
return (ISC_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 {
}
if (result == ISC_R_NOTFOUND)
return (DNS_R_NXDOMAIN);
else if (result != ISC_R_SUCCESS)
return (result);
/*
* And now look for the type.
*/
return (ISC_R_SUCCESS);
if (result == ISC_R_NOTFOUND)
return (DNS_R_NXRRSET);
return (result);
}
void
{
/*
* Unlink the name from the old section
*/
}
void
{
}
void
{
}
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
void
if (dns_name_dynamic(*item))
}
void
}
void
}
void
}
unsigned int *flagsp)
{
isc_region_t r;
unsigned int flags;
isc_buffer_remainingregion(&buffer, &r);
if (r.length < DNS_MESSAGE_HEADERLEN)
return (ISC_R_UNEXPECTEDEND);
return (ISC_R_SUCCESS);
}
unsigned int clear_from;
return (DNS_R_FORMERR);
else if (want_question_section) {
if (!msg->question_ok)
return (DNS_R_FORMERR);
} else
/*
* We now clear most flags and then set QR, ensuring that the
* reply's flags will be in a reasonable state.
*/
/*
* This saves the query TSIG status, if the query was signed, and
* reserves space in the reply for the TSIG.
*/
unsigned int otherlen = 0;
otherlen = 6;
if (result != ISC_R_SUCCESS) {
msg->sig_reserved = 0;
return (result);
}
}
msg->free_saved = 0;
}
return (ISC_R_SUCCESS);
}
/*
* Get the OPT record for 'msg'.
*/
}
/*
* Set the OPT record for 'msg'.
*/
/*
* The space required for an OPT record is:
*
* 1 byte for the name
* 2 bytes for the type
* 2 bytes for the class
* 4 bytes for the ttl
* 2 bytes for the rdata length
* ---------------------------------
* 11 bytes
*
* plus the length of the rdata.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS) {
msg->opt_reserved = 0;
goto cleanup;
}
return (ISC_R_SUCCESS);
return (result);
}
/*
* Get the TSIG record and owner for 'msg'.
*/
}
/*
* Set the TSIG key for 'msg'
*/
if (msg->sig_reserved != 0) {
msg->sig_reserved = 0;
}
}
msg->sig_reserved);
if (result != ISC_R_SUCCESS) {
msg->sig_reserved = 0;
return (result);
}
}
}
return (ISC_R_SUCCESS);
}
/*
* Get the TSIG key for 'msg'
*/
}
isc_region_t r;
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
isc_buffer_usedregion(buf, &r);
if (result != ISC_R_SUCCESS)
goto cleanup;
return (result);
return (ISC_R_NOMEMORY);
}
isc_buffer_t **querytsig) {
isc_region_t r;
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
return (result);
dns_rdata_toregion(&rdata, &r);
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
/*
* Get the SIG(0) record for 'msg'.
*/
/* If dns_message_getsig0 is called on a rendered message
* after the SIG(0) has been applied, we need to return the
* root name, not NULL.
*/
*owner = dns_rootname;
else
}
}
isc_region_t r;
unsigned int x;
/*
* Set the SIG(0) key for 'msg'
*/
/*
* The space required for an SIG(0) record is:
*
* 1 byte for the name
* 2 bytes for the type
* 2 bytes for the class
* 4 bytes for the ttl
* 2 bytes for the type covered
* 1 byte for the algorithm
* 1 bytes for the labels
* 4 bytes for the original ttl
* 4 bytes for the signature expiration
* 4 bytes for the signature inception
* 2 bytes for the key tag
* n bytes for the signer's name
* x bytes for the signature
* ---------------------------------
* 27 + n + x bytes
*/
if (result != ISC_R_SUCCESS) {
msg->sig_reserved = 0;
return (result);
}
if (result != ISC_R_SUCCESS) {
msg->sig_reserved = 0;
return (result);
}
}
return (ISC_R_SUCCESS);
}
/*
* Get the SIG(0) key for 'msg'
*/
}
void
}
return (ISC_R_NOTFOUND);
if (msg->verify_attempted == 0)
return (DNS_R_NOTVERIFIEDYET);
if (!dns_name_hasbuffer(signer)) {
if (result != ISC_R_SUCCESS)
return (result);
}
if (result != ISC_R_SUCCESS)
return (result);
else
} else {
else
/*
* If msg->tsigstatus & tsig.error are both
* dns_rcode_noerror, the message must have been
* verified, which means msg->tsigkey will be
* non-NULL.
*/
} else {
if (result == ISC_R_SUCCESS)
}
}
}
return (result);
}
void
msg->verified_sig = 0;
msg->verify_attempted = 0;
msg->timeadjust = 0;
}
}
}
#ifdef SKAN_MSG_DEBUG
void
}
}
}
#endif
isc_buffer_t b, msgb;
return (ISC_R_SUCCESS);
#ifdef SKAN_MSG_DEBUG
#endif
else
} else {
/*
* This can occur when the message is a dynamic update, since
* the rdata length checking is relaxed. This should not
* happen in a well-formed message, since the SIG(0) is only
* looked for in the additional section, and the dynamic update
* meta-records are in the prerequisite and update sections.
*/
return (ISC_R_UNEXPECTEDEND);
if (result != ISC_R_SUCCESS)
return (result);
return (DNS_R_KEYUNAUTHORIZED);
dns_rdatatype_key /* SIG(0) */,
if (result != ISC_R_SUCCESS) {
/* XXXBEW Should possibly create a fetch here */
goto freesig;
/* XXXBEW Should call a validator here */
goto freesig;
}
for (;
result == ISC_R_SUCCESS;
{
if (result != ISC_R_SUCCESS)
continue;
{
dst_key_free(&key);
continue;
}
dst_key_free(&key);
if (result == ISC_R_SUCCESS)
break;
}
if (result == ISC_R_NOMORE)
if (dns_rdataset_isassociated(&keyset))
return (result);
}
}
const dns_master_style_t *style,
isc_buffer_t *target) {
return (ISC_R_SUCCESS);
if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
} else {
}
}
if (result != ISC_R_SUCCESS) {
return (result);
}
do {
if (section == DNS_SECTION_ANSWER &&
if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
continue;
if (seensoa &&
(flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
continue;
}
if (section == DNS_SECTION_QUESTION) {
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
target);
} else {
target);
}
if (result != ISC_R_SUCCESS)
return (result);
}
} while (result == ISC_R_SUCCESS);
if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
(flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
}
if (result == ISC_R_NOMORE)
return (result);
}
static isc_result_t
int i;
/*
* Note: This routine needs to handle malformed ECS options.
*/
return (DNS_R_OPTERR);
return (DNS_R_OPTERR);
return (DNS_R_OPTERR);
return (DNS_R_OPTERR);
for (i = 0; i < addrbytes; i ++)
switch (family) {
case 0:
return (DNS_R_OPTERR);
break;
case 1:
return (DNS_R_OPTERR);
break;
case 2:
return (DNS_R_OPTERR);
break;
default:
"Unsupported family %u", family);
return (ISC_R_SUCCESS);
}
return (ISC_R_SUCCESS);
}
const dns_master_style_t *style,
{
char buf[sizeof("1234567890")];
unsigned char *optdata;
switch (section) {
case DNS_PSEUDOSECTION_OPT:
return (ISC_R_SUCCESS);
if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
}
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
if (mbz != 0) {
} else
if (result != ISC_R_SUCCESS)
return (ISC_R_SUCCESS);
/*
* Print EDNS info, if any.
*
* WARNING: The option contents may be malformed as
* dig +ednsopt=value:<content> does not validity
* checking.
*/
while (isc_buffer_remaininglength(&optbuf) != 0) {
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
if (optcode == DNS_OPT_NSID) {
} else if (optcode == DNS_OPT_COOKIE) {
} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
optlen);
if (result == ISC_R_NOSPACE)
return (result);
if (result == ISC_R_SUCCESS) {
continue;
}
} else if (optcode == DNS_OPT_EXPIRE) {
if (optlen == 4) {
target);
if (result != ISC_R_SUCCESS)
return (result);
continue;
}
} else if (optcode == DNS_OPT_PAD) {
} else {
}
if (optlen != 0) {
int i;
for (i = 0; i < optlen; i++) {
const char *sep;
switch (optcode) {
case DNS_OPT_COOKIE:
sep = "";
break;
default:
sep = " ";
break;
}
}
if (optcode == DNS_OPT_COOKIE) {
continue;
}
if (optcode == DNS_OPT_CLIENT_SUBNET) {
continue;
}
/*
* For non-COOKIE options, add a printable
* version
*/
return (ISC_R_NOSPACE);
for (i = 0; i < optlen; i++) {
&optdata[i],
1);
else
}
}
}
return (ISC_R_SUCCESS);
case DNS_PSEUDOSECTION_TSIG:
return (ISC_R_SUCCESS);
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
(flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
return (result);
case DNS_PSEUDOSECTION_SIG0:
return (ISC_R_SUCCESS);
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
(flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
return (result);
}
return (ISC_R_UNEXPECTED);
}
{
char buf[sizeof("1234567890")];
if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
if (result != ISC_R_SUCCESS)
return (result);
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
/*
* The final unnamed flag must be zero.
*/
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
}
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
} else {
if ((sflags & DNS_STYLEFLAG_INDENT) != 0)
}
} else {
}
} else {
}
}
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
}
void
const void *order_arg)
{
}
void
}
int
return (msg->timeadjust);
}
return (ISC_R_NOSPACE);
return (ISC_R_SUCCESS);
}
void
{
}
void
{
}
void
{
}
void
{
}
static void
{
char addrbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
const char *newline = "\n";
const char *space = " ";
int len = 1024;
return;
/*
* Note that these are multiline debug messages. We want a newline
* to appear in the log after each message.
*/
else
do {
break;
if (result == ISC_R_NOSPACE) {
len += 1024;
} else if (result == ISC_R_SUCCESS)
(int)isc_buffer_usedlength(&buffer),
buf);
} while (result == ISC_R_NOSPACE);
}
{
unsigned int len = 0, i;
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* Set Maximum UDP buffer size.
*/
/*
* Set EXTENDED-RCODE and Z to 0.
*/
/*
* Set EDNS options if applicable
*/
if (count != 0U) {
for (i = 0; i < count; i++)
if (len > 0xffffU) {
goto cleanup;
}
if (result != ISC_R_SUCCESS)
goto cleanup;
for (i = 0; i < count; i++) {
}
} else {
}
return (ISC_R_SUCCESS);
return (result);
}
void
}