summaryrefslogtreecommitdiffstats
path: root/lib/dns/message.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/message.c')
-rw-r--r--lib/dns/message.c155
1 files changed, 127 insertions, 28 deletions
diff --git a/lib/dns/message.c b/lib/dns/message.c
index 2b65f0e..d36edba 100644
--- a/lib/dns/message.c
+++ b/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);
+}
OpenPOWER on IntegriCloud