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