diff options
Diffstat (limited to 'contrib/bind9/lib/dns/message.c')
-rw-r--r-- | contrib/bind9/lib/dns/message.c | 155 |
1 files changed, 127 insertions, 28 deletions
diff --git a/contrib/bind9/lib/dns/message.c b/contrib/bind9/lib/dns/message.c index 2b65f0e..d36edba 100644 --- a/contrib/bind9/lib/dns/message.c +++ b/contrib/bind9/lib/dns/message.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -1441,8 +1441,15 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, * the opcode is an update, or the type search is skipped. */ if (result == ISC_R_SUCCESS) { - if (dns_rdatatype_issingleton(rdtype)) - DO_FORMERR; + if (dns_rdatatype_issingleton(rdtype)) { + dns_rdata_t *first; + dns_rdatalist_fromrdataset(rdataset, + &rdatalist); + first = ISC_LIST_HEAD(rdatalist->rdata); + INSIST(first != NULL); + if (dns_rdata_compare(rdata, first) != 0) + DO_FORMERR; + } } if (result == ISC_R_NOTFOUND) { @@ -2112,6 +2119,30 @@ dns_message_renderend(dns_message_t *msg) { } /* + * 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. + */ + if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) && + (msg->flags & DNS_MESSAGEFLAG_TC) != 0) + { + isc_buffer_t *buf; + + msgresetnames(msg, DNS_SECTION_ANSWER); + buf = msg->buffer; + dns_message_renderreset(msg); + msg->buffer = buf; + isc_buffer_clear(msg->buffer); + isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN); + dns_compress_rollback(msg->cctx, 0); + result = dns_message_rendersection(msg, DNS_SECTION_QUESTION, + 0); + if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) + return (result); + } + + /* * If we've got an OPT record, render it. */ if (msg->opt != NULL) { @@ -2136,30 +2167,6 @@ dns_message_renderend(dns_message_t *msg) { } /* - * If we're adding a TSIG or SIG(0) to a truncated message, - * clear all rdatasets from the message except for the question - * before adding the TSIG or SIG(0). If the question doesn't fit, - * don't include it. - */ - if ((msg->tsigkey != NULL || msg->sig0key != NULL) && - (msg->flags & DNS_MESSAGEFLAG_TC) != 0) - { - isc_buffer_t *buf; - - msgresetnames(msg, DNS_SECTION_ANSWER); - buf = msg->buffer; - dns_message_renderreset(msg); - msg->buffer = buf; - isc_buffer_clear(msg->buffer); - isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN); - dns_compress_rollback(msg->cctx, 0); - result = dns_message_rendersection(msg, DNS_SECTION_QUESTION, - 0); - if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) - return (result); - } - - /* * If we're adding a TSIG record, generate and render it. */ if (msg->tsigkey != NULL) { @@ -2633,9 +2640,9 @@ dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) { return (ISC_R_SUCCESS); cleanup: + dns_rdataset_disassociate(opt); dns_message_puttemprdataset(msg, &opt); return (result); - } dns_rdataset_t * @@ -3449,3 +3456,95 @@ dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) { isc_buffer_putstr(target, opcodetext[opcode]); return (ISC_R_SUCCESS); } + +isc_result_t +dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp, + unsigned int version, isc_uint16_t udpsize, + unsigned int flags, dns_ednsopt_t *ednsopts, size_t count) +{ + dns_rdataset_t *rdataset = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdata_t *rdata = NULL; + isc_result_t result; + size_t len = 0, i; + + REQUIRE(DNS_MESSAGE_VALID(message)); + REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); + + result = dns_message_gettemprdatalist(message, &rdatalist); + if (result != ISC_R_SUCCESS) + return (result); + result = dns_message_gettemprdata(message, &rdata); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdataset(message, &rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdataset_init(rdataset); + + rdatalist->type = dns_rdatatype_opt; + rdatalist->covers = 0; + + /* + * Set Maximum UDP buffer size. + */ + rdatalist->rdclass = udpsize; + + /* + * Set EXTENDED-RCODE and Z to 0. + */ + rdatalist->ttl = (version << 16); + rdatalist->ttl |= (flags & 0xffff); + + /* + * Set EDNS options if applicable + */ + if (count != 0U) { + isc_buffer_t *buf = NULL; + for (i = 0; i < count; i++) + len += ednsopts[i].length + 4; + + if (len > 0xffffU) { + result = ISC_R_NOSPACE; + goto cleanup; + } + + result = isc_buffer_allocate(message->mctx, &buf, len); + if (result != ISC_R_SUCCESS) + goto cleanup; + + for (i = 0; i < count; i++) { + isc_buffer_putuint16(buf, ednsopts[i].code); + isc_buffer_putuint16(buf, ednsopts[i].length); + isc_buffer_putmem(buf, ednsopts[i].value, + ednsopts[i].length); + } + rdata->data = isc_buffer_base(buf); + rdata->length = len; + dns_message_takebuffer(message, &buf); + } else { + rdata->data = NULL; + rdata->length = 0; + } + + rdata->rdclass = rdatalist->rdclass; + rdata->type = rdatalist->type; + rdata->flags = 0; + + ISC_LIST_INIT(rdatalist->rdata); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + result = dns_rdatalist_tordataset(rdatalist, rdataset); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + *rdatasetp = rdataset; + return (ISC_R_SUCCESS); + + cleanup: + if (rdata != NULL) + dns_message_puttemprdata(message, &rdata); + if (rdataset != NULL) + dns_message_puttemprdataset(message, &rdataset); + if (rdatalist != NULL) + dns_message_puttemprdatalist(message, &rdatalist); + return (result); +} |