query.c
Go to the documentation of this file.
/*
* Copyright (c) 2011 NLNet Labs. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#include "daemon/dnshandler.h"
#include "daemon/engine.h"
#include "file.h"
#include "util.h"
#include "wire/axfr.h"
#include "wire/query.h"
const char* query_str = "query";
query_type*
query_create(void)
{
query_type* q = NULL;
CHECKALLOC(q = (query_type*) malloc(sizeof(query_type)));
q->buffer = NULL;
q->tsig_rr = NULL;
q->axfr_fd = NULL;
q->buffer = buffer_create(PACKET_BUFFER_SIZE);
if (!q->buffer) {
query_cleanup(q);
return NULL;
}
q->tsig_rr = tsig_rr_create();
if (!q->tsig_rr) {
query_cleanup(q);
return NULL;
}
q->edns_rr = edns_rr_create();
if (!q->edns_rr) {
query_cleanup(q);
return NULL;
}
query_reset(q, UDP_MAX_MESSAGE_LEN, 0);
return q;
}
void
query_reset(query_type* q, size_t maxlen, int is_tcp)
{
if (!q) {
return;
}
q->addrlen = sizeof(q->addr);
q->maxlen = maxlen;
q->reserved_space = 0;
buffer_clear(q->buffer);
tsig_rr_reset(q->tsig_rr, NULL, NULL);
edns_rr_reset(q->edns_rr);
q->tsig_prepare_it = 1;
q->tsig_update_it = 1;
q->tsig_sign_it = 1;
q->tcp = is_tcp;
/* qname, qtype, qclass */
q->zone = NULL;
/* domain, opcode, cname count, delegation, compression, temp */
q->axfr_is_done = 0;
if (q->axfr_fd) {
ods_fclose(q->axfr_fd);
q->axfr_fd = NULL;
}
q->serial = 0;
q->startpos = 0;
}
static query_state
query_error(query_type* q, ldns_pkt_rcode rcode)
{
size_t limit = 0;
if (!q) {
return QUERY_DISCARDED;
}
limit = buffer_limit(q->buffer);
buffer_clear(q->buffer);
buffer_pkt_set_qr(q->buffer);
buffer_pkt_set_rcode(q->buffer, rcode);
buffer_pkt_set_ancount(q->buffer, 0);
buffer_pkt_set_nscount(q->buffer, 0);
buffer_pkt_set_arcount(q->buffer, 0);
buffer_set_position(q->buffer, limit);
return QUERY_PROCESSED;
}
static query_state
query_formerr(query_type* q)
{
ldns_pkt_opcode opcode = LDNS_PACKET_QUERY;
if (!q) {
return QUERY_DISCARDED;
}
opcode = buffer_pkt_opcode(q->buffer);
/* preserve the RD flag, clear the rest */
buffer_pkt_set_flags(q->buffer, buffer_pkt_flags(q->buffer) & 0x0100U);
buffer_pkt_set_opcode(q->buffer, opcode);
buffer_pkt_set_qdcount(q->buffer, 0);
ods_log_debug("[%s] formerr", query_str);
return query_error(q, LDNS_RCODE_FORMERR);
}
static query_state
query_servfail(query_type* q)
{
if (!q) {
return QUERY_DISCARDED;
}
ods_log_debug("[%s] servfail", query_str);
buffer_set_position(q->buffer, 0);
buffer_set_limit(q->buffer, BUFFER_PKT_HEADER_SIZE);
buffer_pkt_set_qdcount(q->buffer, 0);
return query_error(q, LDNS_RCODE_SERVFAIL);
}
static query_state
query_notimpl(query_type* q)
{
if (!q) {
return QUERY_DISCARDED;
}
ods_log_debug("[%s] notimpl", query_str);
return query_error(q, LDNS_RCODE_NOTIMPL);
}
static query_state
query_refused(query_type* q)
{
if (!q) {
return QUERY_DISCARDED;
}
ods_log_debug("[%s] refused", query_str);
return query_error(q, LDNS_RCODE_REFUSED);
}
static query_state
query_notauth(query_type* q)
{
if (!q) {
return QUERY_DISCARDED;
}
ods_log_debug("[%s] notauth", query_str);
return query_error(q, LDNS_RCODE_NOTAUTH);
}
static int
query_parse_soa(buffer_type* buffer, uint32_t* serial)
{
ldns_rr_type type = 0;
ods_log_assert(buffer);
if (!buffer_available(buffer, 10)) {
ods_log_error("[%s] bad soa: packet too short", query_str);
return 0;
}
type = (ldns_rr_type) buffer_read_u16(buffer);
if (type != LDNS_RR_TYPE_SOA) {
ods_log_error("[%s] bad soa: rr is not soa (%d)", query_str, type);
return 0;
}
(void)buffer_read_u16(buffer);
(void)buffer_read_u32(buffer);
/* rdata length */
if (!buffer_available(buffer, buffer_read_u16(buffer))) {
ods_log_error("[%s] bad soa: missing rdlength", query_str);
return 0;
}
/* MNAME */
if (!buffer_skip_dname(buffer)) {
ods_log_error("[%s] bad soa: missing mname", query_str);
return 0;
}
/* RNAME */
if (!buffer_skip_dname(buffer)) {
ods_log_error("[%s] bad soa: missing rname", query_str);
return 0;
}
if (serial) {
*serial = buffer_read_u32(buffer);
}
return 1;
}
static query_state
query_process_notify(query_type* q, ldns_rr_type qtype, engine_type* engine)
{
dnsin_type* dnsin = NULL;
uint16_t count = 0;
uint16_t rrcount = 0;
uint32_t serial = 0;
size_t pos = 0;
char address[128];
if (!engine || !q || !q->zone) {
return QUERY_DISCARDED;
}
ods_log_assert(engine->dnshandler);
ods_log_assert(q->zone->name);
ods_log_verbose("[%s] incoming notify for zone %s", query_str,
q->zone->name);
if (buffer_pkt_rcode(q->buffer) != LDNS_RCODE_NOERROR ||
buffer_pkt_qr(q->buffer) ||
!buffer_pkt_aa(q->buffer) ||
buffer_pkt_tc(q->buffer) ||
buffer_pkt_rd(q->buffer) ||
buffer_pkt_ra(q->buffer) ||
buffer_pkt_ad(q->buffer) ||
buffer_pkt_cd(q->buffer) ||
buffer_pkt_qdcount(q->buffer) != 1 ||
buffer_pkt_ancount(q->buffer) > 1 ||
qtype != LDNS_RR_TYPE_SOA) {
return query_formerr(q);
}
if (!q->zone->adinbound || q->zone->adinbound->type != ADAPTER_DNS) {
ods_log_error("[%s] zone %s is not configured to have input dns "
"adapter", query_str, q->zone->name);
return query_notauth(q);
}
ods_log_assert(q->zone->adinbound->config);
dnsin = (dnsin_type*) q->zone->adinbound->config;
if (!acl_find(dnsin->allow_notify, &q->addr, q->tsig_rr)) {
if (addr2ip(q->addr, address, sizeof(address))) {
ods_log_info("[%s] unauthorized notify for zone %s from %s: "
"no acl matches", query_str, q->zone->name, address);
} else {
ods_log_info("[%s] unauthorized notify for zone %s from unknown "
"source: no acl matches", query_str, q->zone->name);
}
return query_notauth(q);
}
ods_log_assert(q->zone->xfrd);
/* skip header and question section */
buffer_skip(q->buffer, BUFFER_PKT_HEADER_SIZE);
count = buffer_pkt_qdcount(q->buffer);
for (rrcount = 0; rrcount < count; rrcount++) {
if (!buffer_skip_rr(q->buffer, 1)) {
if (addr2ip(q->addr, address, sizeof(address))) {
ods_log_info("[%s] dropped packet: zone %s received bad "
"notify from %s (bad question section)", query_str,
q->zone->name, address);
} else {
ods_log_info("[%s] dropped packet: zone %s received bad "
"notify from unknown source (bad question section)",
query_str, q->zone->name);
}
return QUERY_DISCARDED;
}
}
pos = buffer_position(q->buffer);
/* examine answer section */
count = buffer_pkt_ancount(q->buffer);
if (count) {
if (!buffer_skip_dname(q->buffer) ||
!query_parse_soa(q->buffer, &serial)) {
if (addr2ip(q->addr, address, sizeof(address))) {
ods_log_info("[%s] dropped packet: zone %s received bad "
"notify from %s (bad soa in answer section)", query_str,
q->zone->name, address);
} else {
ods_log_info("[%s] dropped packet: zone %s received bad "
"notify from unknown source (bad soa in answer section)",
query_str, q->zone->name);
}
return QUERY_DISCARDED;
}
pthread_mutex_lock(&q->zone->xfrd->serial_lock);
if (!util_serial_gt(serial, q->zone->xfrd->serial_disk)) {
if (addr2ip(q->addr, address, sizeof(address))) {
ods_log_info("[%s] ignore notify from %s: already got "
"zone %s serial %u on disk (received %u)", query_str,
address, q->zone->name, q->zone->xfrd->serial_disk,
serial);
} else {
ods_log_info("[%s] ignore notify: already got zone %s "
"serial %u on disk (received %u)", query_str,
q->zone->name, q->zone->xfrd->serial_disk, serial);
}
pthread_mutex_unlock(&q->zone->xfrd->serial_lock);
} else if (q->zone->xfrd->serial_notify_acquired) {
pthread_mutex_unlock(&q->zone->xfrd->serial_lock);
if (addr2ip(q->addr, address, sizeof(address))) {
ods_log_info("[%s] ignore notify from %s: zone %s "
"transfer in progress", query_str, address,
q->zone->name);
} else {
ods_log_info("[%s] ignore notify: zone %s transfer in "
"progress", query_str, q->zone->name);
}
} else {
q->zone->xfrd->serial_notify = serial;
q->zone->xfrd->serial_notify_acquired = time_now();
pthread_mutex_unlock(&q->zone->xfrd->serial_lock);
/* forward notify to xfrd */
if (addr2ip(q->addr, address, sizeof(address))) {
ods_log_verbose("[%s] forward notify for zone %s from client %s",
query_str, q->zone->name, address);
} else {
ods_log_verbose("[%s] forward notify for zone %s", query_str,
q->zone->name);
}
xfrd_set_timer_now(q->zone->xfrd);
dnshandler_fwd_notify(engine->dnshandler, buffer_begin(q->buffer),
buffer_remaining(q->buffer));
}
} else { /* Empty answer section, no SOA. We still need to process
the notify according to the RFC */
/* forward notify to xfrd */
if (addr2ip(q->addr, address, sizeof(address))) {
ods_log_verbose("[%s] forward notify for zone %s from client %s",
query_str, q->zone->name, address);
} else {
ods_log_verbose("[%s] forward notify for zone %s", query_str,
q->zone->name);
}
xfrd_set_timer_now(q->zone->xfrd);
dnshandler_fwd_notify(engine->dnshandler, buffer_begin(q->buffer),
buffer_remaining(q->buffer));
}
/* send notify ok */
buffer_pkt_set_qr(q->buffer);
buffer_pkt_set_aa(q->buffer);
buffer_pkt_set_ancount(q->buffer, 0);
buffer_clear(q->buffer); /* lim = pos, pos = 0; */
buffer_set_position(q->buffer, pos);
buffer_set_limit(q->buffer, buffer_capacity(q->buffer));
q->reserved_space = edns_rr_reserved_space(q->edns_rr);
q->reserved_space += tsig_rr_reserved_space(q->tsig_rr);
return QUERY_PROCESSED;
}
static query_state
query_process_ixfr(query_type* q)
{
uint16_t count = 0;
ods_log_assert(q);
ods_log_assert(q->buffer);
ods_log_assert(buffer_pkt_qdcount(q->buffer) == 1);
/* skip header and question section */
buffer_skip(q->buffer, BUFFER_PKT_HEADER_SIZE);
if (!buffer_skip_rr(q->buffer, 1)) {
ods_log_error("[%s] dropped packet: zone %s received bad ixfr "
"request (bad question section)", query_str, q->zone->name);
return QUERY_DISCARDED;
}
/* answer section is empty */
ods_log_assert(buffer_pkt_ancount(q->buffer) == 0);
/* examine auth section */
q->startpos = buffer_position(q->buffer);
count = buffer_pkt_nscount(q->buffer);
if (count) {
if (!buffer_skip_dname(q->buffer) ||
!query_parse_soa(q->buffer, &(q->serial))) {
ods_log_error("[%s] dropped packet: zone %s received bad ixfr "
"request (bad soa in auth section)", query_str, q->zone->name);
return QUERY_DISCARDED;
}
ods_log_debug("[%s] found ixfr request zone %s serial=%u", query_str,
q->zone->name, q->serial);
return QUERY_PROCESSED;
}
ods_log_debug("[%s] ixfr request zone %s has no auth section", query_str,
q->zone->name);
q->serial = 0;
return QUERY_PROCESSED;
}
static int
response_add_rrset(response_type* r, rrset_type* rrset,
ldns_pkt_section section)
{
if (!r || !rrset || !section) {
return 0;
}
/* duplicates? */
r->sections[r->rrset_count] = section;
r->rrsets[r->rrset_count] = rrset;
++r->rrset_count;
return 1;
}
static int
response_encode_rr(query_type* q, ldns_rr* rr, ldns_pkt_section section)
{
uint8_t *data = NULL;
size_t size = 0;
ldns_status status = LDNS_STATUS_OK;
ods_log_assert(q);
ods_log_assert(rr);
ods_log_assert(section);
status = ldns_rr2wire(&data, rr, section, &size);
if (status != LDNS_STATUS_OK) {
ods_log_error("[%s] unable to send good response: ldns_rr2wire() "
"failed (%s)", query_str, ldns_get_errorstr_by_id(status));
return 0;
}
buffer_write(q->buffer, (const void*) data, size);
LDNS_FREE(data);
return 1;
}
static uint16_t
response_encode_rrset(query_type* q, rrset_type* rrset, ldns_pkt_section section)
{
rrsig_type* rrsig;
uint16_t i = 0;
uint16_t added = 0;
ods_log_assert(q);
ods_log_assert(rrset);
ods_log_assert(section);
for (i = 0; i < rrset->rr_count; i++) {
added += response_encode_rr(q, rrset->rrs[i].rr, section);
}
if (q->edns_rr && q->edns_rr->dnssec_ok) {
while((rrsig = collection_iterator(rrset->rrsigs))) {
added += response_encode_rr(q, rrsig->rr, section);
}
}
/* truncation? */
return added;
}
static void
response_encode(query_type* q, response_type* r)
{
uint16_t counts[LDNS_SECTION_ANY];
ldns_pkt_section s = LDNS_SECTION_QUESTION;
size_t i = 0;
ods_log_assert(q);
ods_log_assert(r);
for (s = LDNS_SECTION_ANSWER; s < LDNS_SECTION_ANY; s++) {
counts[s] = 0;
}
for (s = LDNS_SECTION_ANSWER; s < LDNS_SECTION_ANY; s++) {
for (i = 0; i < r->rrset_count; i++) {
if (r->sections[i] == s) {
counts[s] += response_encode_rrset(q, r->rrsets[i], s);
}
}
}
buffer_pkt_set_ancount(q->buffer, counts[LDNS_SECTION_ANSWER]);
buffer_pkt_set_nscount(q->buffer, counts[LDNS_SECTION_AUTHORITY]);
buffer_pkt_set_arcount(q->buffer, counts[LDNS_SECTION_ADDITIONAL]);
buffer_pkt_set_qr(q->buffer);
buffer_pkt_set_aa(q->buffer);
}
static query_state
query_response(query_type* q, ldns_rr_type qtype)
{
rrset_type* rrset = NULL;
response_type r;
if (!q || !q->zone) {
return QUERY_DISCARDED;
}
r.rrset_count = 0;
pthread_mutex_lock(&q->zone->zone_lock);
rrset = zone_lookup_rrset(q->zone, q->zone->apex, qtype);
if (rrset) {
if (!response_add_rrset(&r, rrset, LDNS_SECTION_ANSWER)) {
pthread_mutex_unlock(&q->zone->zone_lock);
return query_servfail(q);
}
/* NS RRset goes into Authority Section */
rrset = zone_lookup_rrset(q->zone, q->zone->apex, LDNS_RR_TYPE_NS);
if (rrset) {
if (!response_add_rrset(&r, rrset, LDNS_SECTION_AUTHORITY)) {
pthread_mutex_unlock(&q->zone->zone_lock);
return query_servfail(q);
}
} /* else: not having NS RRs is not fatal */
} else if (qtype != LDNS_RR_TYPE_SOA) {
rrset = zone_lookup_rrset(q->zone, q->zone->apex, LDNS_RR_TYPE_SOA);
if (!rrset) {
pthread_mutex_unlock(&q->zone->zone_lock);
return query_servfail(q);
}
if (!response_add_rrset(&r, rrset, LDNS_SECTION_AUTHORITY)) {
pthread_mutex_unlock(&q->zone->zone_lock);
return query_servfail(q);
}
} else {
pthread_mutex_unlock(&q->zone->zone_lock);
return query_servfail(q);
}
pthread_mutex_unlock(&q->zone->zone_lock);
response_encode(q, &r);
/* compression */
return QUERY_PROCESSED;
}
void
query_prepare(query_type* q)
{
uint16_t limit = 0;
uint16_t flags = 0;
ods_log_assert(q);
ods_log_assert(q->buffer);
limit = buffer_limit(q->buffer);
flags = buffer_pkt_flags(q->buffer);
flags &= 0x0100U; /* preserve the rd flag */
flags |= 0x8000U; /* set the qr flag */
buffer_pkt_set_flags(q->buffer, flags);
buffer_clear(q->buffer);
buffer_set_position(q->buffer, limit);
buffer_set_limit(q->buffer, buffer_capacity(q->buffer));
q->reserved_space = edns_rr_reserved_space(q->edns_rr);
q->reserved_space += tsig_rr_reserved_space(q->tsig_rr);
}
static query_state
query_process_query(query_type* q, ldns_rr_type qtype, engine_type* engine)
{
dnsout_type* dnsout = NULL;
if (!q || !q->zone) {
return QUERY_DISCARDED;
}
ods_log_assert(q->zone->name);
ods_log_debug("[%s] incoming query qtype=%s for zone %s", query_str,
rrset_type2str(qtype), q->zone->name);
/* sanity checks */
if (buffer_pkt_qdcount(q->buffer) != 1 || buffer_pkt_tc(q->buffer)) {
buffer_pkt_set_flags(q->buffer, 0);
return query_formerr(q);
}
if (buffer_pkt_ancount(q->buffer) != 0 ||
(qtype != LDNS_RR_TYPE_IXFR && buffer_pkt_nscount(q->buffer) != 0)) {
buffer_pkt_set_flags(q->buffer, 0);
return query_formerr(q);
}
/* acl */
if (!q->zone->adoutbound || q->zone->adoutbound->type != ADAPTER_DNS) {
ods_log_error("[%s] zone %s is not configured to have output dns "
"adapter", query_str, q->zone->name);
return query_refused(q);
}
ods_log_assert(q->zone->adoutbound->config);
dnsout = (dnsout_type*) q->zone->adoutbound->config;
/* acl also in use for soa and other queries */
if (!acl_find(dnsout->provide_xfr, &q->addr, q->tsig_rr)) {
ods_log_debug("[%s] zone %s acl query refused", query_str,
q->zone->name);
return query_refused(q);
}
query_prepare(q);
/* ixfr? */
if (qtype == LDNS_RR_TYPE_IXFR) {
ods_log_assert(q->zone->name);
ods_log_debug("[%s] incoming ixfr request serial=%u for zone %s",
query_str, q->serial, q->zone->name);
return ixfr(q, engine);
}
/* axfr? */
if (qtype == LDNS_RR_TYPE_AXFR) {
ods_log_assert(q->zone->name);
ods_log_debug("[%s] incoming axfr request for zone %s",
query_str, q->zone->name);
return axfr(q, engine, 0);
}
/* (soa) query */
if (qtype == LDNS_RR_TYPE_SOA) {
ods_log_assert(q->zone->name);
ods_log_debug("[%s] incoming soa request for zone %s",
query_str, q->zone->name);
return soa_request(q, engine);
}
/* other qtypes */
return query_response(q, qtype);
}
static query_state
query_process_update(query_type* q)
{
if (!q || !q->zone) {
return QUERY_DISCARDED;
}
ods_log_debug("[%s] dynamic update not implemented", query_str);
return query_notimpl(q);
}
static ldns_pkt_rcode
query_process_tsig(query_type* q)
{
if (!q || !q->tsig_rr) {
return LDNS_RCODE_SERVFAIL;
}
if (q->tsig_rr->status == TSIG_ERROR) {
return LDNS_RCODE_FORMERR;
}
if (q->tsig_rr->status == TSIG_OK) {
if (!tsig_rr_lookup(q->tsig_rr)) {
ods_log_debug("[%s] tsig unknown key/algorithm", query_str);
return LDNS_RCODE_REFUSED;
}
buffer_set_limit(q->buffer, q->tsig_rr->position);
buffer_pkt_set_arcount(q->buffer, buffer_pkt_arcount(q->buffer)-1);
tsig_rr_prepare(q->tsig_rr);
tsig_rr_update(q->tsig_rr, q->buffer, buffer_limit(q->buffer));
if (!tsig_rr_verify(q->tsig_rr)) {
ods_log_debug("[%s] bad tsig signature", query_str);
return LDNS_RCODE_NOTAUTH;
}
}
return LDNS_RCODE_NOERROR;
}
static ldns_pkt_rcode
query_process_edns(query_type* q)
{
if (!q || !q->edns_rr) {
return LDNS_RCODE_SERVFAIL;
}
if (q->edns_rr->status == EDNS_ERROR) {
/* The only error is VERSION not implemented */
return LDNS_RCODE_FORMERR;
}
if (q->edns_rr->status == EDNS_OK) {
/* Only care about UDP size larger than normal... */
if (!q->tcp && q->edns_rr->maxlen > UDP_MAX_MESSAGE_LEN) {
if (q->edns_rr->maxlen < EDNS_MAX_MESSAGE_LEN) {
q->maxlen = q->edns_rr->maxlen;
} else {
q->maxlen = EDNS_MAX_MESSAGE_LEN;
}
}
/* Strip the OPT resource record off... */
buffer_set_position(q->buffer, q->edns_rr->position);
buffer_set_limit(q->buffer, q->edns_rr->position);
buffer_pkt_set_arcount(q->buffer, buffer_pkt_arcount(q->buffer) - 1);
}
return LDNS_RCODE_NOERROR;
}
static int
query_find_tsig(query_type* q)
{
size_t saved_pos = 0;
size_t rrcount = 0;
size_t i = 0;
ods_log_assert(q);
ods_log_assert(q->tsig_rr);
ods_log_assert(q->buffer);
if (buffer_pkt_arcount(q->buffer) == 0) {
q->tsig_rr->status = TSIG_NOT_PRESENT;
return 1;
}
saved_pos = buffer_position(q->buffer);
rrcount = buffer_pkt_qdcount(q->buffer) + buffer_pkt_ancount(q->buffer) +
buffer_pkt_nscount(q->buffer);
buffer_set_position(q->buffer, BUFFER_PKT_HEADER_SIZE);
for (i=0; i < rrcount; i++) {
if (!buffer_skip_rr(q->buffer, i < buffer_pkt_qdcount(q->buffer))) {
buffer_set_position(q->buffer, saved_pos);
return 0;
}
}
rrcount = buffer_pkt_arcount(q->buffer);
ods_log_assert(rrcount != 0);
if (!tsig_rr_parse(q->tsig_rr, q->buffer)) {
ods_log_debug("[%s] got bad tsig", query_str);
return 0;
}
if (q->tsig_rr->status != TSIG_NOT_PRESENT) {
--rrcount;
}
if (rrcount) {
if (edns_rr_parse(q->edns_rr, q->buffer)) {
--rrcount;
}
}
if (rrcount && q->tsig_rr->status == TSIG_NOT_PRESENT) {
/* see if tsig is after the edns record */
if (!tsig_rr_parse(q->tsig_rr, q->buffer)) {
ods_log_debug("[%s] got bad tsig", query_str);
return 0;
}
if (q->tsig_rr->status != TSIG_NOT_PRESENT) {
--rrcount;
}
}
if (rrcount > 0) {
ods_log_debug("[%s] too many additional rrs", query_str);
return 0;
}
buffer_set_position(q->buffer, saved_pos);
return 1;
}
query_state
query_process(query_type* q, engine_type* engine)
{
ldns_status status = LDNS_STATUS_OK;
ldns_pkt* pkt = NULL;
ldns_rr* rr = NULL;
ldns_pkt_rcode rcode = LDNS_RCODE_NOERROR;
ldns_pkt_opcode opcode = LDNS_PACKET_QUERY;
ldns_rr_type qtype = LDNS_RR_TYPE_SOA;
ods_log_assert(engine);
ods_log_assert(q);
ods_log_assert(q->buffer);
if (buffer_limit(q->buffer) < BUFFER_PKT_HEADER_SIZE) {
ods_log_debug("[%s] drop query: packet too small", query_str);
return QUERY_DISCARDED; /* too small */
}
if (buffer_pkt_qr(q->buffer)) {
ods_log_debug("[%s] drop query: qr bit set", query_str);
return QUERY_DISCARDED; /* not a query */
}
/* parse packet */
status = ldns_wire2pkt(&pkt, buffer_current(q->buffer),
buffer_remaining(q->buffer));
if (status != LDNS_STATUS_OK) {
ods_log_debug("[%s] got bad packet: %s", query_str,
ldns_get_errorstr_by_id(status));
return query_formerr(q);
}
rr = ldns_rr_list_rr(ldns_pkt_question(pkt), 0);
if (!rr) {
ods_log_debug("[%s] no RRset in query section, ignoring", query_str);
return QUERY_DISCARDED; /* no RRset in query */
}
pthread_mutex_lock(&engine->zonelist->zl_lock);
/* we can just lookup the zone, because we will only handle SOA queries,
zone transfers, updates and notifies */
q->zone = zonelist_lookup_zone_by_dname(engine->zonelist, ldns_rr_owner(rr),
ldns_rr_get_class(rr));
/* don't answer for zones that are just added */
if (q->zone && q->zone->zl_status == ZONE_ZL_ADDED) {
ods_log_assert(q->zone->name);
ods_log_warning("[%s] zone %s just added, don't answer for now",
query_str, q->zone->name);
q->zone = NULL;
}
pthread_mutex_unlock(&engine->zonelist->zl_lock);
if (!q->zone) {
ods_log_debug("[%s] zone not found", query_str);
return query_servfail(q);
}
/* see if it is tsig signed */
if (!query_find_tsig(q)) {
return query_formerr(q);
}
/* else: valid tsig, or no tsig present */
ods_log_debug("[%s] tsig %s", query_str, tsig_status2str(q->tsig_rr->status));
/* get opcode, qtype, ixfr=serial */
opcode = ldns_pkt_get_opcode(pkt);
qtype = ldns_rr_get_type(rr);
if (qtype == LDNS_RR_TYPE_IXFR) {
ods_log_assert(q->zone->name);
ods_log_debug("[%s] incoming ixfr request for zone %s",
query_str, q->zone->name);
if (query_process_ixfr(q) != QUERY_PROCESSED) {
return query_formerr(q);
}
}
/* process tsig */
rcode = query_process_tsig(q);
if (rcode != LDNS_RCODE_NOERROR) {
return query_error(q, rcode);
}
/* process edns */
rcode = query_process_edns(q);
if (rcode != LDNS_RCODE_NOERROR) {
/* We should not return FORMERR, but BADVERS (=16).
* BADVERS is created with Ext. RCODE, followed by RCODE.
* Ext. RCODE is set to 1, RCODE must be 0 (getting 0x10 = 16).
* Thus RCODE = NOERROR = NSD_RC_OK. */
return query_error(q, LDNS_RCODE_NOERROR);
}
/* handle incoming request */
ldns_pkt_free(pkt);
switch (opcode) {
case LDNS_PACKET_NOTIFY:
return query_process_notify(q, qtype, engine);
case LDNS_PACKET_QUERY:
return query_process_query(q, qtype, engine);
case LDNS_PACKET_UPDATE:
return query_process_update(q);
default:
break;
}
return query_notimpl(q);
}
static int
query_overflow(query_type* q)
{
ods_log_assert(q);
ods_log_assert(q->buffer);
return buffer_position(q->buffer) > (q->maxlen - q->reserved_space);
}
void
query_add_optional(query_type* q, engine_type* engine)
{
edns_data_type* edns = NULL;
if (!q || !engine) {
return;
}
if (q->edns_rr) {
edns = &engine->edns;
switch (q->edns_rr->status) {
case EDNS_NOT_PRESENT:
break;
case EDNS_OK:
ods_log_debug("[%s] add edns opt ok", query_str);
if (q->edns_rr->dnssec_ok) {
edns->ok[7] = 0x80;
} else {
edns->ok[7] = 0x00;
}
buffer_write(q->buffer, edns->ok, OPT_LEN);
/* fill with NULLs */
buffer_write(q->buffer, edns->rdata_none, OPT_RDATA);
buffer_pkt_set_arcount(q->buffer,
buffer_pkt_arcount(q->buffer) + 1);
break;
case EDNS_ERROR:
ods_log_debug("[%s] add edns opt err", query_str);
if (q->edns_rr->dnssec_ok) {
edns->ok[7] = 0x80;
} else {
edns->ok[7] = 0x00;
}
buffer_write(q->buffer, edns->error, OPT_LEN);
buffer_write(q->buffer, edns->rdata_none, OPT_RDATA);
buffer_pkt_set_arcount(q->buffer,
buffer_pkt_arcount(q->buffer) + 1);
break;
default:
break;
}
}
if (!q->tsig_rr) {
return;
}
if (q->tsig_rr->status != TSIG_NOT_PRESENT) {
if (q->tsig_rr->status == TSIG_ERROR ||
q->tsig_rr->error_code != LDNS_RCODE_NOERROR) {
ods_log_debug("[%s] add tsig err", query_str);
tsig_rr_error(q->tsig_rr);
tsig_rr_append(q->tsig_rr, q->buffer);
buffer_pkt_set_arcount(q->buffer,
buffer_pkt_arcount(q->buffer)+1);
} else if (q->tsig_rr->status == TSIG_OK &&
q->tsig_rr->error_code == LDNS_RCODE_NOERROR) {
ods_log_debug("[%s] add tsig ok", query_str);
if (q->tsig_prepare_it)
tsig_rr_prepare(q->tsig_rr);
if (q->tsig_update_it)
tsig_rr_update(q->tsig_rr, q->buffer,
buffer_position(q->buffer));
if (q->tsig_sign_it) {
tsig_rr_sign(q->tsig_rr);
tsig_rr_append(q->tsig_rr, q->buffer);
buffer_pkt_set_arcount(q->buffer,
buffer_pkt_arcount(q->buffer)+1);
}
}
}
}
int
query_add_rr(query_type* q, ldns_rr* rr)
{
size_t i = 0;
size_t tc_mark = 0;
size_t rdlength_pos = 0;
uint16_t rdlength = 0;
ods_log_assert(q);
ods_log_assert(q->buffer);
ods_log_assert(rr);
/* set truncation mark, in case rr does not fit */
tc_mark = buffer_position(q->buffer);
/* owner type class ttl */
if (!buffer_available(q->buffer, ldns_rdf_size(ldns_rr_owner(rr)))) {
goto query_add_rr_tc;
}
buffer_write_rdf(q->buffer, ldns_rr_owner(rr));
if (!buffer_available(q->buffer, sizeof(uint16_t) + sizeof(uint16_t) +
sizeof(uint32_t) + sizeof(rdlength))) {
goto query_add_rr_tc;
}
buffer_write_u16(q->buffer, (uint16_t) ldns_rr_get_type(rr));
buffer_write_u16(q->buffer, (uint16_t) ldns_rr_get_class(rr));
buffer_write_u32(q->buffer, (uint32_t) ldns_rr_ttl(rr));
/* skip rdlength */
rdlength_pos = buffer_position(q->buffer);
buffer_skip(q->buffer, sizeof(rdlength));
/* write rdata */
for (i=0; i < ldns_rr_rd_count(rr); i++) {
if (!buffer_available(q->buffer, ldns_rdf_size(ldns_rr_rdf(rr, i)))) {
goto query_add_rr_tc;
}
buffer_write_rdf(q->buffer, ldns_rr_rdf(rr, i));
}
if (!query_overflow(q)) {
/* write rdlength */
rdlength = buffer_position(q->buffer) - rdlength_pos - sizeof(rdlength);
buffer_write_u16_at(q->buffer, rdlength_pos, rdlength);
/* position updated by buffer_write() */
return 1;
}
query_add_rr_tc:
buffer_set_position(q->buffer, tc_mark);
ods_log_assert(!query_overflow(q));
return 0;
}
void
query_cleanup(query_type* q)
{
if (!q) {
return;
}
if (q->axfr_fd) {
ods_fclose(q->axfr_fd);
q->axfr_fd = NULL;
}
buffer_cleanup(q->buffer);
tsig_rr_cleanup(q->tsig_rr);
edns_rr_cleanup(q->edns_rr);
free(q);
}
EDNS_ERROR
Definition: edns.h:67
engine_struct::edns
edns_data_type edns
Definition: engine.h:72
edns_rr_cleanup
void edns_rr_cleanup(edns_rr_type *err)
Definition: edns.c:170
buffer_pkt_opcode
ldns_pkt_opcode buffer_pkt_opcode(buffer_type *buffer)
Definition: buffer.c:846
EDNS_NOT_PRESENT
Definition: edns.h:65
axfr.h
query_create
query_type * query_create(void)
Definition: query.c:48
zonelist_struct::zl_lock
pthread_mutex_t zl_lock
Definition: zonelist.h:50
tsig_rr_update
void tsig_rr_update(tsig_rr_type *trr, buffer_type *buffer, size_t length)
Definition: tsig.c:559
query_struct::maxlen
size_t maxlen
Definition: query.h:64
engine_struct::zonelist
zonelist_type * zonelist
Definition: engine.h:69
tsig_rr_struct::status
tsig_status status
Definition: tsig.h:124
rrset_struct::rr_count
size_t rr_count
Definition: rrset.h:65
edns_rr_parse
int edns_rr_parse(edns_rr_type *err, buffer_type *buffer)
Definition: edns.c:107
buffer_pkt_rd
int buffer_pkt_rd(buffer_type *buffer)
Definition: buffer.c:906
query_struct::tsig_sign_it
unsigned tsig_sign_it
Definition: query.h:88
rrset_type2str
const char * rrset_type2str(ldns_rr_type type)
Definition: rrset.c:158
engine.h
query_struct::tcp
int tcp
Definition: query.h:71
query_cleanup
void query_cleanup(query_type *q)
Definition: query.c:1092
adapter_struct::config
void * config
Definition: adapter.h:61
query_struct::tsig_rr
tsig_rr_type * tsig_rr
Definition: query.h:67
UDP_MAX_MESSAGE_LEN
#define UDP_MAX_MESSAGE_LEN
Definition: query.h:42
tsig_rr_parse
int tsig_rr_parse(tsig_rr_type *trr, buffer_type *buffer)
Definition: tsig.c:322
buffer_pkt_arcount
uint16_t buffer_pkt_arcount(buffer_type *buffer)
Definition: buffer.c:1066
dnsin_struct
Definition: addns.h:49
query_struct::zone
zone_type * zone
Definition: query.h:77
BUFFER_PKT_HEADER_SIZE
#define BUFFER_PKT_HEADER_SIZE
Definition: buffer.h:43
tsig_rr_struct::error_code
uint16_t error_code
Definition: tsig.h:142
edns_rr_reset
void edns_rr_reset(edns_rr_type *err)
Definition: edns.c:90
rrset_struct::rrsigs
collection_t rrsigs
Definition: rrset.h:66
query_str
const char * query_str
Definition: query.c:40
xfrd_struct::serial_notify
uint32_t serial_notify
Definition: xfrd.h:111
query_struct::tsig_update_it
unsigned tsig_update_it
Definition: query.h:87
ZONE_ZL_ADDED
Definition: zone.h:35
buffer_pkt_qdcount
uint16_t buffer_pkt_qdcount(buffer_type *buffer)
Definition: buffer.c:994
OPT_RDATA
#define OPT_RDATA
Definition: edns.h:44
buffer_skip
void buffer_skip(buffer_type *buffer, ssize_t count)
Definition: buffer.c:150
buffer_pkt_set_flags
void buffer_pkt_set_flags(buffer_type *buffer, uint16_t flags)
Definition: buffer.c:798
buffer_read_u16
uint16_t buffer_read_u16(buffer_type *buffer)
Definition: buffer.c:721
buffer_skip_rr
int buffer_skip_rr(buffer_type *buffer, unsigned qrr)
Definition: buffer.c:342
buffer_pkt_set_qdcount
void buffer_pkt_set_qdcount(buffer_type *buffer, uint16_t count)
Definition: buffer.c:1006
buffer_clear
void buffer_clear(buffer_type *buffer)
Definition: buffer.c:99
xfrd_struct::serial_notify_acquired
time_t serial_notify_acquired
Definition: xfrd.h:117
response_struct::rrset_count
size_t rrset_count
Definition: query.h:97
QUERY_DISCARDED
Definition: query.h:48
edns_rr_struct::position
size_t position
Definition: edns.h:78
adapter_struct::type
adapter_mode type
Definition: adapter.h:58
zone_struct::zl_status
zone_zl_status zl_status
Definition: zone.h:72
query_struct::reserved_space
size_t reserved_space
Definition: query.h:65
query_reset
void query_reset(query_type *q, size_t maxlen, int is_tcp)
Definition: query.c:80
buffer_pkt_qr
int buffer_pkt_qr(buffer_type *buffer)
Definition: buffer.c:810
query_struct::edns_rr
edns_rr_type * edns_rr
Definition: query.h:69
edns_rr_struct::dnssec_ok
int dnssec_ok
Definition: edns.h:80
tsig_rr_reset
void tsig_rr_reset(tsig_rr_type *trr, tsig_algo_type *algo, tsig_key_type *key)
Definition: tsig.c:292
tsig_rr_append
void tsig_rr_append(tsig_rr_type *trr, buffer_type *buffer)
Definition: tsig.c:672
query.h
query_struct
Definition: query.h:59
ADAPTER_DNS
Definition: adapter.h:42
query_struct::tsig_prepare_it
unsigned tsig_prepare_it
Definition: query.h:86
dnshandler.h
buffer_write
void buffer_write(buffer_type *buffer, const void *data, size_t count)
Definition: buffer.c:538
query_struct::addr
struct sockaddr_storage addr
Definition: query.h:61
response_struct::rrsets
rrset_type * rrsets[QUERY_RESPONSE_MAX_RRSET]
Definition: query.h:99
buffer_current
uint8_t * buffer_current(buffer_type *buffer)
Definition: buffer.c:438
zone_struct::adoutbound
adapter_type * adoutbound
Definition: zone.h:75
zone_struct::zone_lock
pthread_mutex_t zone_lock
Definition: zone.h:86
buffer_pkt_ancount
uint16_t buffer_pkt_ancount(buffer_type *buffer)
Definition: buffer.c:1018
buffer_limit
size_t buffer_limit(buffer_type *buffer)
Definition: buffer.c:373
tsig_rr_create
tsig_rr_type * tsig_rr_create()
Definition: tsig.c:274
tsig_rr_prepare
void tsig_rr_prepare(tsig_rr_type *trr)
Definition: tsig.c:537
buffer_pkt_set_ancount
void buffer_pkt_set_ancount(buffer_type *buffer, uint16_t count)
Definition: buffer.c:1030
tsig_status2str
const char * tsig_status2str(tsig_status status)
Definition: tsig.c:759
buffer_pkt_set_nscount
void buffer_pkt_set_nscount(buffer_type *buffer, uint16_t count)
Definition: buffer.c:1054
buffer_set_limit
void buffer_set_limit(buffer_type *buffer, size_t limit)
Definition: buffer.c:385
buffer_cleanup
void buffer_cleanup(buffer_type *buffer)
Definition: buffer.c:1145
zonelist_lookup_zone_by_dname
zone_type * zonelist_lookup_zone_by_dname(zonelist_type *zonelist, ldns_rdf *dname, ldns_rr_class klass)
Definition: zonelist.c:182
edns_rr_create
edns_rr_type * edns_rr_create()
Definition: edns.c:50
dnsout_struct::provide_xfr
acl_type * provide_xfr
Definition: addns.h:62
buffer_pkt_flags
uint16_t buffer_pkt_flags(buffer_type *buffer)
Definition: buffer.c:786
xfrd_struct::serial_lock
pthread_mutex_t serial_lock
Definition: xfrd.h:97
axfr
query_state axfr(query_type *q, engine_type *engine, int fallback)
Definition: axfr.c:152
TSIG_NOT_PRESENT
Definition: tsig.h:56
buffer_struct
Definition: buffer.h:112
rrsig_struct::rr
ldns_rr * rr
Definition: rrset.h:45
EDNS_OK
Definition: edns.h:66
TSIG_OK
Definition: tsig.h:57
tsig_rr_cleanup
void tsig_rr_cleanup(tsig_rr_type *trr)
Definition: tsig.c:832
zone_struct::adinbound
adapter_type * adinbound
Definition: zone.h:74
buffer_capacity
size_t buffer_capacity(buffer_type *buffer)
Definition: buffer.c:401
buffer_skip_dname
int buffer_skip_dname(buffer_type *buffer)
Definition: buffer.c:310
dnsin_struct::allow_notify
acl_type * allow_notify
Definition: addns.h:51
buffer_read_u32
uint32_t buffer_read_u32(buffer_type *buffer)
Definition: buffer.c:736
query_add_optional
void query_add_optional(query_type *q, engine_type *engine)
Definition: query.c:956
buffer_pkt_set_opcode
void buffer_pkt_set_opcode(buffer_type *buffer, ldns_pkt_opcode opcode)
Definition: buffer.c:858
query_struct::serial
uint32_t serial
Definition: query.h:82
query_state
enum query_enum query_state
Definition: query.h:52
query_struct::buffer
buffer_type * buffer
Definition: query.h:73
PACKET_BUFFER_SIZE
#define PACKET_BUFFER_SIZE
Definition: buffer.h:50
EDNS_MAX_MESSAGE_LEN
#define EDNS_MAX_MESSAGE_LEN
Definition: edns.h:47
tsig_rr_verify
int tsig_rr_verify(tsig_rr_type *trr)
Definition: tsig.c:650
buffer_write_u16
void buffer_write_u16(buffer_type *buffer, uint16_t data)
Definition: buffer.c:565
QUERY_PROCESSED
Definition: query.h:47
query_process
query_state query_process(query_type *q, engine_type *engine)
Definition: query.c:842
buffer_write_u32
void buffer_write_u32(buffer_type *buffer, uint32_t data)
Definition: buffer.c:578
buffer_pkt_set_aa
void buffer_pkt_set_aa(buffer_type *buffer)
Definition: buffer.c:882
tsig_rr_error
void tsig_rr_error(tsig_rr_type *trr)
Definition: tsig.c:742
query_struct::startpos
size_t startpos
Definition: query.h:83
query_struct::axfr_is_done
unsigned axfr_is_done
Definition: query.h:85
edns_data_struct
Definition: edns.h:54
response_struct
Definition: query.h:96
buffer_pkt_aa
int buffer_pkt_aa(buffer_type *buffer)
Definition: buffer.c:870
ixfr
query_state ixfr(query_type *q, engine_type *engine)
Definition: axfr.c:389
rr_struct::rr
ldns_rr * rr
Definition: rrset.h:52
dnsout_struct
Definition: addns.h:61
buffer_pkt_nscount
uint16_t buffer_pkt_nscount(buffer_type *buffer)
Definition: buffer.c:1042
acl_find
acl_type * acl_find(acl_type *acl, struct sockaddr_storage *addr, tsig_rr_type *trr)
Definition: acl.c:437
zone_lookup_rrset
rrset_type * zone_lookup_rrset(zone_type *zone, ldns_rdf *owner, ldns_rr_type type)
Definition: zone.c:512
tsig_rr_struct::position
size_t position
Definition: tsig.h:125
buffer_write_u16_at
void buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data)
Definition: buffer.c:512
buffer_set_position
void buffer_set_position(buffer_type *buffer, size_t pos)
Definition: buffer.c:137
engine_struct
Definition: engine.h:51
query_struct::addrlen
socklen_t addrlen
Definition: query.h:62
xfrd_set_timer_now
void xfrd_set_timer_now(xfrd_type *xfrd)
Definition: xfrd.c:454
buffer_available
int buffer_available(buffer_type *buffer, size_t count)
Definition: buffer.c:487
edns_rr_struct::maxlen
size_t maxlen
Definition: edns.h:79
buffer_pkt_ad
int buffer_pkt_ad(buffer_type *buffer)
Definition: buffer.c:930
zone_struct::name
const char * name
Definition: zone.h:69
tsig_rr_lookup
int tsig_rr_lookup(tsig_rr_type *trr)
Definition: tsig.c:469
rrset_struct
Definition: rrset.h:59
buffer_remaining
size_t buffer_remaining(buffer_type *buffer)
Definition: buffer.c:463
buffer_pkt_set_rcode
void buffer_pkt_set_rcode(buffer_type *buffer, ldns_pkt_rcode rcode)
Definition: buffer.c:966
OPT_LEN
#define OPT_LEN
Definition: edns.h:43
soa_request
query_state soa_request(query_type *q, engine_type *engine)
Definition: axfr.c:53
buffer_write_rdf
void buffer_write_rdf(buffer_type *buffer, ldns_rdf *rdf)
Definition: buffer.c:591
buffer_pkt_ra
int buffer_pkt_ra(buffer_type *buffer)
Definition: buffer.c:918
tsig_rr_sign
void tsig_rr_sign(tsig_rr_type *trr)
Definition: tsig.c:629
query_prepare
void query_prepare(query_type *q)
Definition: query.c:612
query_add_rr
int query_add_rr(query_type *q, ldns_rr *rr)
Definition: query.c:1035
edns_rr_reserved_space
size_t edns_rr_reserved_space(edns_rr_type *err)
Definition: edns.c:160
buffer_position
size_t buffer_position(buffer_type *buffer)
Definition: buffer.c:125
rrsig_struct
Definition: rrset.h:44
TSIG_ERROR
Definition: tsig.h:58
query_struct::axfr_fd
FILE * axfr_fd
Definition: query.h:81
edns_data_struct::error
unsigned char error[OPT_LEN]
Definition: edns.h:56
edns_data_struct::ok
unsigned char ok[OPT_LEN]
Definition: edns.h:55
buffer_pkt_set_arcount
void buffer_pkt_set_arcount(buffer_type *buffer, uint16_t count)
Definition: buffer.c:1078
edns_rr_struct::status
edns_status status
Definition: edns.h:77
buffer_pkt_cd
int buffer_pkt_cd(buffer_type *buffer)
Definition: buffer.c:942
zone_struct::xfrd
xfrd_type * xfrd
Definition: zone.h:82
response_struct::sections
ldns_pkt_section sections[QUERY_RESPONSE_MAX_RRSET]
Definition: query.h:98
dnshandler_fwd_notify
void dnshandler_fwd_notify(dnshandler_type *dnshandler, uint8_t *pkt, size_t len)
Definition: dnshandler.c:231
addr2ip
int addr2ip(struct sockaddr_storage addr, char *ip, size_t len)
Definition: acl.c:416
zone_struct::apex
ldns_rdf * apex
Definition: zone.h:61
edns_data_struct::rdata_none
unsigned char rdata_none[OPT_RDATA]
Definition: edns.h:57
buffer_pkt_set_qr
void buffer_pkt_set_qr(buffer_type *buffer)
Definition: buffer.c:822
buffer_begin
uint8_t * buffer_begin(buffer_type *buffer)
Definition: buffer.c:426
xfrd_struct::serial_disk
uint32_t serial_disk
Definition: xfrd.h:113
buffer_pkt_rcode
ldns_pkt_rcode buffer_pkt_rcode(buffer_type *buffer)
Definition: buffer.c:954
buffer_create
buffer_type * buffer_create(size_t capacity)
Definition: buffer.c:78
engine_struct::dnshandler
dnshandler_type * dnshandler
Definition: engine.h:70
buffer_pkt_tc
int buffer_pkt_tc(buffer_type *buffer)
Definition: buffer.c:894
tsig_rr_reserved_space
size_t tsig_rr_reserved_space(tsig_rr_type *trr)
Definition: tsig.c:713
rrset_struct::rrs
rr_type * rrs
Definition: rrset.h:64