1 /*
2  * answer.c -- manipulating query answers and encoding them.
3  *
4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include "config.h"
11 
12 #include <string.h>
13 
14 #include "answer.h"
15 #include "packet.h"
16 #include "query.h"
17 
18 void
answer_init(answer_type * answer)19 answer_init(answer_type *answer)
20 {
21 	answer->rrset_count = 0;
22 }
23 
24 int
answer_add_rrset(answer_type * answer,rr_section_type section,domain_type * domain,rrset_type * rrset)25 answer_add_rrset(answer_type *answer, rr_section_type section,
26 		 domain_type *domain, rrset_type *rrset)
27 {
28 	size_t i;
29 
30 	assert(section >= ANSWER_SECTION && section < RR_SECTION_COUNT);
31 	assert(domain);
32 	assert(rrset);
33 
34 	/* Don't add an RRset multiple times.  */
35 	for (i = 0; i < answer->rrset_count; ++i) {
36 		if (answer->rrsets[i] == rrset &&
37 			answer->domains[i]->number == domain->number) {
38 			if (section < answer->section[i]) {
39 				answer->section[i] = section;
40 				return 1;
41 			} else {
42 				return 0;
43 			}
44 		}
45 	}
46 
47 	if (answer->rrset_count >= MAXRRSPP) {
48 		/* XXX: Generate warning/error? */
49 		return 0;
50 	}
51 
52 	answer->section[answer->rrset_count] = section;
53 	answer->domains[answer->rrset_count] = domain;
54 	answer->rrsets[answer->rrset_count] = rrset;
55 	++answer->rrset_count;
56 
57 	return 1;
58 }
59 
60 void
encode_answer(query_type * q,const answer_type * answer)61 encode_answer(query_type *q, const answer_type *answer)
62 {
63 	uint16_t counts[RR_SECTION_COUNT];
64 	rr_section_type section;
65 	size_t i;
66 	int minimal_respsize = IPV4_MINIMAL_RESPONSE_SIZE;
67 	int done = 0;
68 
69 #if defined(INET6) && defined(MINIMAL_RESPONSES)
70 	if (q->addr.ss_family == AF_INET6)
71 		minimal_respsize = IPV6_MINIMAL_RESPONSE_SIZE;
72 #endif
73 
74 	for (section = ANSWER_SECTION; section < RR_SECTION_COUNT; ++section) {
75 		counts[section] = 0;
76 	}
77 
78 	for (section = ANSWER_SECTION;
79 	     !TC(q->packet) && section < RR_SECTION_COUNT;
80 	     ++section) {
81 
82 		for (i = 0; !TC(q->packet) && i < answer->rrset_count; ++i) {
83 			if (answer->section[i] == section) {
84 				counts[section] += packet_encode_rrset(
85 					q,
86 					answer->domains[i],
87 					answer->rrsets[i],
88 					section, minimal_respsize, &done);
89 			}
90 		}
91 #ifdef MINIMAL_RESPONSES
92 		/**
93 		 * done is set prematurely, because the minimal response size
94 		 * has been reached. No need to try adding RRsets in following
95 		 * sections.
96 		 */
97 		if (done) {
98 			/* delegations should have a usable address in it */
99 			if(section == ADDITIONAL_A_SECTION &&
100 				counts[ADDITIONAL_A_SECTION] == 0 &&
101 				q->delegation_domain)
102 				TC_SET(q->packet);
103 			break;
104 		}
105 #endif
106 	}
107 
108 	ANCOUNT_SET(q->packet, counts[ANSWER_SECTION]);
109 	NSCOUNT_SET(q->packet,
110 		    counts[AUTHORITY_SECTION]
111 		    + counts[OPTIONAL_AUTHORITY_SECTION]);
112 	ARCOUNT_SET(q->packet,
113 		    counts[ADDITIONAL_A_SECTION]
114 		    + counts[ADDITIONAL_AAAA_SECTION]
115 		    + counts[ADDITIONAL_OTHER_SECTION]);
116 }
117