xref: /netbsd-src/external/bsd/nsd/dist/answer.c (revision 811a4a0195236f69295602fbee687a174d42af9b)
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