/* * answer.c -- manipulating query answers and encoding them. * * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include #include #include "answer.h" #include "packet.h" #include "query.h" void answer_init(answer_type *answer) { answer->rrset_count = 0; } int answer_add_rrset(answer_type *answer, rr_section_type section, domain_type *domain, rrset_type *rrset) { size_t i; assert(section >= ANSWER_SECTION && section < RR_SECTION_COUNT); assert(domain); assert(rrset); /* Don't add an RRset multiple times. */ for (i = 0; i < answer->rrset_count; ++i) { if (answer->rrsets[i] == rrset) { if (section < answer->section[i]) { answer->section[i] = section; return 1; } else { return 0; } } } if (answer->rrset_count >= MAXRRSPP) { /* XXX: Generate warning/error? */ return 0; } answer->section[answer->rrset_count] = section; answer->domains[answer->rrset_count] = domain; answer->rrsets[answer->rrset_count] = rrset; ++answer->rrset_count; return 1; } void encode_answer(query_type *q, const answer_type *answer) { uint16_t counts[RR_SECTION_COUNT]; rr_section_type section; size_t i; int minimal_respsize = IPV4_MINIMAL_RESPONSE_SIZE; int done = 0; #if defined(INET6) && defined(MINIMAL_RESPONSES) if (q->addr.ss_family == AF_INET6) minimal_respsize = IPV6_MINIMAL_RESPONSE_SIZE; #endif for (section = ANSWER_SECTION; section < RR_SECTION_COUNT; ++section) { counts[section] = 0; } for (section = ANSWER_SECTION; !TC(q->packet) && section < RR_SECTION_COUNT; ++section) { for (i = 0; !TC(q->packet) && i < answer->rrset_count; ++i) { if (answer->section[i] == section) { counts[section] += packet_encode_rrset( q, answer->domains[i], answer->rrsets[i], section, minimal_respsize, &done); } } #ifdef MINIMAL_RESPONSES /** * done is set prematurely, because the minimal response size * has been reached. No need to try adding RRsets in following * sections. */ if (done) { break; } #endif } ANCOUNT_SET(q->packet, counts[ANSWER_SECTION]); NSCOUNT_SET(q->packet, counts[AUTHORITY_SECTION] + counts[OPTIONAL_AUTHORITY_SECTION]); ARCOUNT_SET(q->packet, counts[ADDITIONAL_A_SECTION] + counts[ADDITIONAL_AAAA_SECTION] + counts[ADDITIONAL_OTHER_SECTION]); }