162ac0c33Sjakob /*
262ac0c33Sjakob * answer.c -- manipulating query answers and encoding them.
362ac0c33Sjakob *
4d3fecca9Ssthen * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob *
662ac0c33Sjakob * See LICENSE for the license.
762ac0c33Sjakob *
862ac0c33Sjakob */
962ac0c33Sjakob
10aee1b7aaSsthen #include "config.h"
1162ac0c33Sjakob
1262ac0c33Sjakob #include <string.h>
1362ac0c33Sjakob
1462ac0c33Sjakob #include "answer.h"
1562ac0c33Sjakob #include "packet.h"
1662ac0c33Sjakob #include "query.h"
1762ac0c33Sjakob
1862ac0c33Sjakob void
answer_init(answer_type * answer)1962ac0c33Sjakob answer_init(answer_type *answer)
2062ac0c33Sjakob {
2162ac0c33Sjakob answer->rrset_count = 0;
2262ac0c33Sjakob }
2362ac0c33Sjakob
2462ac0c33Sjakob int
answer_add_rrset(answer_type * answer,rr_section_type section,domain_type * domain,rrset_type * rrset)2562ac0c33Sjakob answer_add_rrset(answer_type *answer, rr_section_type section,
2662ac0c33Sjakob domain_type *domain, rrset_type *rrset)
2762ac0c33Sjakob {
2862ac0c33Sjakob size_t i;
2962ac0c33Sjakob
3062ac0c33Sjakob assert(section >= ANSWER_SECTION && section < RR_SECTION_COUNT);
3162ac0c33Sjakob assert(domain);
3262ac0c33Sjakob assert(rrset);
3362ac0c33Sjakob
3462ac0c33Sjakob /* Don't add an RRset multiple times. */
3562ac0c33Sjakob for (i = 0; i < answer->rrset_count; ++i) {
36aee1b7aaSsthen if (answer->rrsets[i] == rrset &&
37cdb6bbddSbrad answer->domains[i]->number == domain->number) {
3862ac0c33Sjakob if (section < answer->section[i]) {
3962ac0c33Sjakob answer->section[i] = section;
4062ac0c33Sjakob return 1;
4162ac0c33Sjakob } else {
4262ac0c33Sjakob return 0;
4362ac0c33Sjakob }
4462ac0c33Sjakob }
4562ac0c33Sjakob }
4662ac0c33Sjakob
4762ac0c33Sjakob if (answer->rrset_count >= MAXRRSPP) {
4862ac0c33Sjakob /* XXX: Generate warning/error? */
4962ac0c33Sjakob return 0;
5062ac0c33Sjakob }
5162ac0c33Sjakob
5262ac0c33Sjakob answer->section[answer->rrset_count] = section;
5362ac0c33Sjakob answer->domains[answer->rrset_count] = domain;
5462ac0c33Sjakob answer->rrsets[answer->rrset_count] = rrset;
5562ac0c33Sjakob ++answer->rrset_count;
5662ac0c33Sjakob
5762ac0c33Sjakob return 1;
5862ac0c33Sjakob }
5962ac0c33Sjakob
6062ac0c33Sjakob void
encode_answer(query_type * q,const answer_type * answer)6162ac0c33Sjakob encode_answer(query_type *q, const answer_type *answer)
6262ac0c33Sjakob {
6362ac0c33Sjakob uint16_t counts[RR_SECTION_COUNT];
6462ac0c33Sjakob rr_section_type section;
6562ac0c33Sjakob size_t i;
660c2b6c02Sjakob int minimal_respsize = IPV4_MINIMAL_RESPONSE_SIZE;
670c2b6c02Sjakob int done = 0;
680c2b6c02Sjakob
690c2b6c02Sjakob #if defined(INET6) && defined(MINIMAL_RESPONSES)
70*b71395eaSflorian if (q->client_addr.ss_family == AF_INET6)
710c2b6c02Sjakob minimal_respsize = IPV6_MINIMAL_RESPONSE_SIZE;
720c2b6c02Sjakob #endif
7362ac0c33Sjakob
7462ac0c33Sjakob for (section = ANSWER_SECTION; section < RR_SECTION_COUNT; ++section) {
7562ac0c33Sjakob counts[section] = 0;
7662ac0c33Sjakob }
7762ac0c33Sjakob
7862ac0c33Sjakob for (section = ANSWER_SECTION;
7962ac0c33Sjakob !TC(q->packet) && section < RR_SECTION_COUNT;
800c2b6c02Sjakob ++section) {
810c2b6c02Sjakob
8262ac0c33Sjakob for (i = 0; !TC(q->packet) && i < answer->rrset_count; ++i) {
8362ac0c33Sjakob if (answer->section[i] == section) {
8462ac0c33Sjakob counts[section] += packet_encode_rrset(
8562ac0c33Sjakob q,
8662ac0c33Sjakob answer->domains[i],
8762ac0c33Sjakob answer->rrsets[i],
880c2b6c02Sjakob section, minimal_respsize, &done);
8962ac0c33Sjakob }
9062ac0c33Sjakob }
910c2b6c02Sjakob #ifdef MINIMAL_RESPONSES
920c2b6c02Sjakob /**
930c2b6c02Sjakob * done is set prematurely, because the minimal response size
940c2b6c02Sjakob * has been reached. No need to try adding RRsets in following
950c2b6c02Sjakob * sections.
960c2b6c02Sjakob */
970c2b6c02Sjakob if (done) {
98275a8d89Sflorian /* delegations should have a usable address in it */
99275a8d89Sflorian if(section == ADDITIONAL_A_SECTION &&
100275a8d89Sflorian counts[ADDITIONAL_A_SECTION] == 0 &&
101275a8d89Sflorian q->delegation_domain)
102275a8d89Sflorian TC_SET(q->packet);
1030c2b6c02Sjakob break;
1040c2b6c02Sjakob }
1050c2b6c02Sjakob #endif
10662ac0c33Sjakob }
10762ac0c33Sjakob
10862ac0c33Sjakob ANCOUNT_SET(q->packet, counts[ANSWER_SECTION]);
1090c2b6c02Sjakob NSCOUNT_SET(q->packet,
1100c2b6c02Sjakob counts[AUTHORITY_SECTION]
1110c2b6c02Sjakob + counts[OPTIONAL_AUTHORITY_SECTION]);
11262ac0c33Sjakob ARCOUNT_SET(q->packet,
11362ac0c33Sjakob counts[ADDITIONAL_A_SECTION]
11462ac0c33Sjakob + counts[ADDITIONAL_AAAA_SECTION]
11562ac0c33Sjakob + counts[ADDITIONAL_OTHER_SECTION]);
11662ac0c33Sjakob }
117