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
18void
19answer_init(answer_type *answer)
20{
21	answer->rrset_count = 0;
22}
23
24int
25answer_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
60void
61encode_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