* Copyright (C) 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 https://mozilla.org/MPL/2.0/.
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
#include <isc/refcount.h>
#include <dns/compress.h>
#include <dns/masterdump.h>
* \brief Message Handling Module
* When a dns message is received in a buffer, dns_message_parse() is called
* on the memory region. Various items are checked including the format
* of the message (if counts are right, if counts consume the entire sections,
* and if sections consume the entire message) and known pseudo-RRs in the
* additional data section are analyzed and removed.
* TSIG checking is also done at this layer, and any DNSSEC transaction
* signatures should also be checked here.
* Notes on using the gettemp*() and puttemp*() functions:
* These functions return items (names, rdatasets, etc) allocated from some
* internal state of the dns_message_t.
* Names and rdatasets must be put back into the dns_message_t in
* one of two ways. Assume a name was allocated via
* dns_message_gettempname():
*\li (1) insert it into a section, using dns_message_addname().
*\li (2) return it to the message using dns_message_puttempname().
* The same applies to rdatasets.
* On the other hand, offsets, rdatalists and rdatas allocated using
* dns_message_gettemp*() will always be freed automatically
* when the message is reset or destroyed; calling dns_message_puttemp*()
* on rdatalists and rdatas is optional and serves only to enable the item
* to be reused multiple times during the lifetime of the message; offsets
* Buffers allocated using isc_buffer_allocate() can be automatically freed
* as well by giving the buffer to the message using dns_message_takebuffer().
* Doing this will cause the buffer to be freed using isc_buffer_free()
* when the section lists are cleared, such as in a reset or in a destroy.
* Since the buffer itself exists until the message is destroyed, this sort
* of code can be written:
* buffer = isc_buffer_allocate(mctx, 512);
* name = dns_message_gettempname(message, &name);
* dns_name_init(name, NULL);
* result = dns_name_fromtext(name, &source, dns_rootname, 0, buffer);
* dns_message_takebuffer(message, &buffer);
* XXX Needed: ways to set and retrieve EDNS information, add rdata to a
* section, move rdata from one section to another, remove rdata, etc.
#define DNS_MESSAGEFLAG_QR 0x8000U
#define DNS_MESSAGEFLAG_AA 0x0400U
#define DNS_MESSAGEFLAG_TC 0x0200U
#define DNS_MESSAGEFLAG_RD 0x0100U
#define DNS_MESSAGEFLAG_RA 0x0080U
#define DNS_MESSAGEFLAG_AD 0x0020U
#define DNS_MESSAGEFLAG_CD 0x0010U
/*%< EDNS0 extended message flags */
#define DNS_MESSAGEEXTFLAG_DO 0x8000U
/*%< EDNS0 extended OPT codes */
#define DNS_OPT_LLQ 1 /*%< LLQ opt code */
#define DNS_OPT_NSID 3 /*%< NSID opt code */
#define DNS_OPT_CLIENT_SUBNET 8 /*%< client subnet opt code */
#define DNS_OPT_EXPIRE 9 /*%< EXPIRE opt code */
#define DNS_OPT_COOKIE 10 /*%< COOKIE opt code */
#define DNS_OPT_TCP_KEEPALIVE 11 /*%< TCP keepalive opt code */
#define DNS_OPT_PAD 12 /*%< PAD opt code */
#define DNS_OPT_KEY_TAG 14 /*%< Key tag opt code */
#define DNS_OPT_EDE 15 /*%< Extended DNS Error opt code */
#define DNS_OPT_CLIENT_TAG 16 /*%< Client tag opt code */
#define DNS_OPT_SERVER_TAG 17 /*%< Server tag opt code */
/*%< Experimental options [65001...65534] as per RFC6891 */
/*%< The number of EDNS options we know about. */
#define DNS_EDNSOPTIONS 5
#define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD)
#define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO)
#define DNS_MESSAGE_HEADERLEN 12 /*%< 6 uint16_t's */
#define DNS_MESSAGE_MAGIC ISC_MAGIC('M','S','G','@')
#define DNS_MESSAGE_VALID(msg) ISC_MAGIC_VALID(msg, DNS_MESSAGE_MAGIC)
* Ordering here matters. DNS_SECTION_ANY must be the lowest and negative,
* and DNS_SECTION_MAX must be one greater than the last used section.
typedef int dns_section_t;
#define DNS_SECTION_ANY (-1)
#define DNS_SECTION_QUESTION 0
#define DNS_SECTION_ANSWER 1
#define DNS_SECTION_AUTHORITY 2
#define DNS_SECTION_ADDITIONAL 3
#define DNS_SECTION_MAX 4
typedef int dns_pseudosection_t;
#define DNS_PSEUDOSECTION_ANY (-1)
#define DNS_PSEUDOSECTION_OPT 0
#define DNS_PSEUDOSECTION_TSIG 1
#define DNS_PSEUDOSECTION_SIG0 2
#define DNS_PSEUDOSECTION_MAX 3
typedef int dns_messagetextflag_t;
#define DNS_MESSAGETEXTFLAG_NOCOMMENTS 0x0001
#define DNS_MESSAGETEXTFLAG_NOHEADERS 0x0002
#define DNS_MESSAGETEXTFLAG_ONESOA 0x0004
#define DNS_MESSAGETEXTFLAG_OMITSOA 0x0008
* Dynamic update names for these sections.
#define DNS_SECTION_ZONE DNS_SECTION_QUESTION
#define DNS_SECTION_PREREQUISITE DNS_SECTION_ANSWER
#define DNS_SECTION_UPDATE DNS_SECTION_AUTHORITY
* These tell the message library how the created dns_message_t will be used.
#define DNS_MESSAGE_INTENTUNKNOWN 0 /*%< internal use only */
#define DNS_MESSAGE_INTENTPARSE 1 /*%< parsing messages */
#define DNS_MESSAGE_INTENTRENDER 2 /*%< rendering */
* Control behavior of parsing
#define DNS_MESSAGEPARSE_PRESERVEORDER 0x0001 /*%< preserve rdata order */
#define DNS_MESSAGEPARSE_BESTEFFORT 0x0002 /*%< return a message if a
#define DNS_MESSAGEPARSE_CLONEBUFFER 0x0004 /*%< save a copy of the
#define DNS_MESSAGEPARSE_IGNORETRUNCATION 0x0008 /*%< truncation errors are
* Control behavior of rendering
#define DNS_MESSAGERENDER_ORDERED 0x0001 /*%< don't change order */
#define DNS_MESSAGERENDER_PARTIAL 0x0002 /*%< allow a partial rdataset */
#define DNS_MESSAGERENDER_OMITDNSSEC 0x0004 /*%< omit DNSSEC records */
#define DNS_MESSAGERENDER_PREFER_A 0x0008 /*%< prefer A records in
#define DNS_MESSAGERENDER_PREFER_AAAA 0x0010 /*%< prefer AAAA records in
#define DNS_MESSAGERENDER_FILTER_AAAA 0x0020 /*%< filter AAAA records */
typedef struct dns_msgblock dns_msgblock_t;
/* public from here down */
dns_rdataclass_t rdclass;
unsigned int counts[DNS_SECTION_MAX];
/* private from here down */
dns_namelist_t sections[DNS_SECTION_MAX];
dns_name_t *cursors[DNS_SECTION_MAX];
unsigned int from_to_wire : 2;
unsigned int header_ok : 1;
unsigned int question_ok : 1;
unsigned int tcp_continuation : 1;
unsigned int verified_sig : 1;
unsigned int verify_attempted : 1;
unsigned int free_query : 1;
unsigned int free_saved : 1;
unsigned int rdclass_set : 1;
unsigned int opt_reserved;
unsigned int sig_reserved;
unsigned int reserved; /* reserved space (render) */
isc_bufferlist_t scratchpad;
isc_bufferlist_t cleanup;
ISC_LIST(dns_msgblock_t) rdatas;
ISC_LIST(dns_msgblock_t) rdatalists;
ISC_LIST(dns_msgblock_t) offsets;
ISC_LIST(dns_rdata_t) freerdata;
ISC_LIST(dns_rdatalist_t) freerdatalist;
dns_rcode_t querytsigstatus;
dns_name_t *tsigname; /* Owner name of TSIG, if any */
dns_rdataset_t *querytsig;
dns_name_t *sig0name; /* Owner name of SIG0, if any */
dns_rdatasetorderfunc_t order;
dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp);
* This function will allocate some internal blocks of memory that are
* expected to be needed for parsing or rendering nearly any type of message.
*\li 'mctx' be a valid memory context.
*\li 'msgp' be non-null and '*msg' be NULL.
*\li 'intent' must be one of DNS_MESSAGE_INTENTPARSE or
* #DNS_MESSAGE_INTENTRENDER.
*\li The data in "*msg" is set to indicate an unused and empty msg
*\li #ISC_R_NOMEMORY -- out of memory
*\li #ISC_R_SUCCESS -- success
dns_message_reset(dns_message_t *msg, unsigned int intent);
* Reset a message structure to default state. All internal lists are freed
* or reset to a default state as well. This is simply a more efficient
* way to call dns_message_detach() (assuming last reference is hold),
* followed by dns_message_create(), since it avoid many memory allocations.
* If any data loanouts (buffers, names, rdatas, etc) were requested,
* the caller must no longer use them after this call.
* The intended next use of the message will be 'intent'.
*\li 'intent' is DNS_MESSAGE_INTENTPARSE or DNS_MESSAGE_INTENTRENDER
dns_message_attach(dns_message_t *source, dns_message_t **target);
* Attach to message 'source'.
*\li 'source' to be a valid message.
*\li 'target' to be non NULL and '*target' to be NULL.
dns_message_detach(dns_message_t **messagep);
* Detach *messagep from its message.
*\li '*messagep' to be a valid message.
dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
const dns_master_style_t *style,
dns_messagetextflag_t flags,
dns_message_pseudosectiontotext(dns_message_t *msg,
dns_pseudosection_t section,
const dns_master_style_t *style,
dns_messagetextflag_t flags,
* Convert section 'section' or 'pseudosection' of message 'msg' to
* a cleartext representation
* \li See dns_message_totext for meanings of flags.
*\li 'msg' is a valid message.
*\li 'style' is a valid master dump style.
*\li 'target' is a valid buffer.
*\li 'section' is a valid section label.
*\li If the result is success:
* The used space in 'target' is updated.
*\li Note: On error return, *target may be partially filled with data.
dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
dns_messagetextflag_t flags, isc_buffer_t *target);
* Convert all sections of message 'msg' to a cleartext representation
*\li If #DNS_MESSAGETEXTFLAG_NOCOMMENTS is cleared, lines beginning with
* ";;" will be emitted indicating section name.
*\li If #DNS_MESSAGETEXTFLAG_NOHEADERS is cleared, header lines will be
*\li If #DNS_MESSAGETEXTFLAG_ONESOA is set then only print the first
* SOA record in the answer section.
*\li If *#DNS_MESSAGETEXTFLAG_OMITSOA is set don't print any SOA records
* The SOA flags are useful for suppressing the display of the second
* SOA record in an AXFR by setting #DNS_MESSAGETEXTFLAG_ONESOA on the
* first message in an AXFR stream and #DNS_MESSAGETEXTFLAG_OMITSOA on
*\li 'msg' is a valid message.
*\li 'style' is a valid master dump style.
*\li 'target' is a valid buffer.
*\li If the result is success:
* The used space in 'target' is updated.
*\li Note: On error return, *target may be partially filled with data.
dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
* Parse raw wire data in 'source' as a DNS message.
* OPT records are detected and stored in the pseudo-section "opt".
* TSIGs are detected and stored in the pseudo-section "tsig".
* If #DNS_MESSAGEPARSE_PRESERVEORDER is set, or if the opcode of the message
* is UPDATE, a separate dns_name_t object will be created for each RR in the
* message. Each such dns_name_t will have a single rdataset containing the
* single RR, and the order of the RRs in the message is preserved.
* Otherwise, only one dns_name_t object will be created for each unique
* owner name in the section, and each such dns_name_t will have a list
* of rdatasets. To access the names and their data, use
* dns_message_firstname() and dns_message_nextname().
* If #DNS_MESSAGEPARSE_BESTEFFORT is set, errors in message content will
* not be considered FORMERRs. If the entire message can be parsed, it
* will be returned and DNS_R_RECOVERABLE will be returned.
* If #DNS_MESSAGEPARSE_IGNORETRUNCATION is set then return as many complete
* RR's as possible, DNS_R_RECOVERABLE will be returned.
* OPT and TSIG records are always handled specially, regardless of the
* 'preserve_order' setting.
*\li "buffer" be a wire format buffer.
*\li The buffer's data format is correct.
*\li The buffer's contents verify as correct regarding header bits, buffer
*\li #ISC_R_SUCCESS -- all is well
*\li #ISC_R_NOMEMORY -- no memory
*\li #DNS_R_RECOVERABLE -- the message parsed properly, but contained
*\li Many other errors possible XXXMLG
dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
* Begin rendering on a message. Only one call can be made to this function
* The compression context is "owned" by the message library until
* dns_message_renderend() is called. It must be invalidated by the caller.
* The buffer is "owned" by the message library until dns_message_renderend()