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->client_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