Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 19ff2ba4e9513c692f03f152b5fcb7f0 > files > 37

bind-9.3.6-25.P1.el5_11.11.src.rpm

diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h
index 960c11a..01db5bc 100644
--- a/lib/dns/include/dns/message.h
+++ b/lib/dns/include/dns/message.h
@@ -198,6 +198,8 @@ struct dns_message {
 	unsigned int			verify_attempted : 1;
 	unsigned int			free_query : 1;
 	unsigned int			free_saved : 1;
+	unsigned int			tkey : 1;
+	unsigned int			rdclass_set : 1;
 
 	unsigned int			opt_reserved;
 	unsigned int			sig_reserved;
@@ -1313,6 +1315,15 @@ dns_message_gettimeadjust(dns_message_t *msg);
  *	msg be a valid message.
  */
 
+void
+dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass);
+/*%<
+ * Set the expected class of records in the response.
+ *
+ * Requires:
+ * \li   msg be a valid message with parsing intent.
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_MESSAGE_H */
diff --git a/lib/dns/message.c b/lib/dns/message.c
index 5eacad0..6d6f1e2 100644
--- a/lib/dns/message.c
+++ b/lib/dns/message.c
@@ -402,6 +402,8 @@ msginit(dns_message_t *m) {
 	m->saved.base = NULL;
 	m->saved.length = 0;
 	m->free_saved = 0;
+	m->tkey = 0;
+	m->rdclass_set = 0;
 	m->querytsig = NULL;
 }
 
@@ -1050,13 +1052,19 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 		 * If this class is different than the one we already read,
 		 * this is an error.
 		 */
-		if (msg->state == DNS_SECTION_ANY) {
-			msg->state = DNS_SECTION_QUESTION;
+		if (msg->rdclass_set == 0) {
 			msg->rdclass = rdclass;
+			msg->rdclass_set = 1;
 		} else if (msg->rdclass != rdclass)
 			DO_FORMERR;
 
 		/*
+		 * Is this a TKEY query?
+		 */
+		if (rdtype == dns_rdatatype_tkey)
+			msg->tkey = 1;
+
+		/*
 		 * Can't ask the same question twice.
 		 */
 		result = dns_message_find(name, rdclass, rdtype, 0, NULL);
@@ -1201,12 +1209,12 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 		 * If there was no question section, we may not yet have
 		 * established a class.  Do so now.
 		 */
-		if (msg->state == DNS_SECTION_ANY &&
+		if (msg->rdclass_set == 0 &&
 		    rdtype != dns_rdatatype_opt &&	/* class is UDP SIZE */
 		    rdtype != dns_rdatatype_tsig &&	/* class is ANY */
 		    rdtype != dns_rdatatype_tkey) {	/* class is undefined */
 			msg->rdclass = rdclass;
-			msg->state = DNS_SECTION_QUESTION;
+			msg->rdclass_set = 1;
 		}
 
 		/*
@@ -1216,7 +1224,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 		if (msg->opcode != dns_opcode_update
 		    && rdtype != dns_rdatatype_tsig
 		    && rdtype != dns_rdatatype_opt
-		    && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
+		    && rdtype != dns_rdatatype_key /* in a TKEY query */
 		    && rdtype != dns_rdatatype_sig /* SIG(0) */
 		    && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
 		    && msg->rdclass != dns_rdataclass_any
@@ -1224,6 +1232,16 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 			DO_FORMERR;
 
 		/*
+		 * If this is not a TKEY query/response then the KEY
+		 * record's class needs to match.
+		 */
+		if (msg->opcode != dns_opcode_update && !msg->tkey &&
+		    rdtype == dns_rdatatype_key &&
+		    msg->rdclass != dns_rdataclass_any &&
+		    msg->rdclass != rdclass)
+			DO_FORMERR;
+
+		/*
 		 * Special type handling for TSIG, OPT, and TKEY.
 		 */
 		if (rdtype == dns_rdatatype_tsig) {
@@ -1337,6 +1355,10 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 				skip_name_search = ISC_TRUE;
 				skip_type_search = ISC_TRUE;
 				issigzero = ISC_TRUE;
+			} else {
+				if (msg->rdclass != dns_rdataclass_any &&
+				    msg->rdclass != rdclass)
+					DO_FORMERR;
 			}
 		} else
 			covers = 0;
@@ -1572,6 +1594,7 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
 	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
 
 	msg->header_ok = 1;
+	msg->state = DNS_SECTION_QUESTION;
 
 	/*
 	 * -1 means no EDNS.
@@ -3252,3 +3275,15 @@ dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
 	isc_buffer_putstr(target, opcodetext[opcode]);
 	return (ISC_R_SUCCESS);
 }
+
+void
+dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
+
+	REQUIRE(DNS_MESSAGE_VALID(msg));
+	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
+	REQUIRE(msg->state == DNS_SECTION_ANY);
+	REQUIRE(msg->rdclass_set == 0);
+
+	msg->rdclass = rdclass;
+	msg->rdclass_set = 1;
+}
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index b0f982e..6760844 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -5396,6 +5396,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
 			goto done;
 	}
 
+	dns_message_setclass(message, fctx->res->rdclass);
+
 	result = dns_message_parse(message, &devent->buffer, 0);
 	if (result != ISC_R_SUCCESS) {
 		switch (result) {
@@ -5475,6 +5477,12 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
 	 */
 	log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx);
 
+	if (message->rdclass != fctx->res->rdclass) {
+		resend = ISC_TRUE;
+		FCTXTRACE("bad class");
+		goto done;
+	}
+
 	/*
 	 * If the message is signed, check the signature.  If not, this
 	 * returns success anyway.
diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c
index ca2d857..1553fe5 100644
--- a/lib/dns/xfrin.c
+++ b/lib/dns/xfrin.c
@@ -1191,6 +1191,8 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
 	msg->tsigctx = xfr->tsigctx;
 	xfr->tsigctx = NULL;
 
+	dns_message_setclass(msg, xfr->rdclass);
+
 	if (xfr->nmsg > 0)
 		msg->tcp_continuation = 1;