mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-24 00:29:58 -05:00
outbound queries via serviced outside_network queries.
git-svn-id: file:///svn/unbound/trunk@327 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
1a90ff7b67
commit
b461dc4111
13 changed files with 501 additions and 150 deletions
|
|
@ -162,6 +162,7 @@ static void daemon_setup_modules(struct daemon* daemon)
|
||||||
daemon->env->cfg = daemon->cfg;
|
daemon->env->cfg = daemon->cfg;
|
||||||
daemon->env->alloc = &daemon->superalloc;
|
daemon->env->alloc = &daemon->superalloc;
|
||||||
daemon->env->worker = NULL;
|
daemon->env->worker = NULL;
|
||||||
|
daemon->env->send_packet = &worker_send_packet;
|
||||||
daemon->env->send_query = &worker_send_query;
|
daemon->env->send_query = &worker_send_query;
|
||||||
for(i=0; i<daemon->num_modules; i++) {
|
for(i=0; i<daemon->num_modules; i++) {
|
||||||
log_info("init module %d: %s", i, daemon->modfunc[i]->name);
|
log_info("init module %d: %s", i, daemon->modfunc[i]->name);
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,12 @@
|
||||||
#include "daemon/daemon.h"
|
#include "daemon/daemon.h"
|
||||||
#include "util/netevent.h"
|
#include "util/netevent.h"
|
||||||
#include "util/config_file.h"
|
#include "util/config_file.h"
|
||||||
|
#include "util/module.h"
|
||||||
#include "util/region-allocator.h"
|
#include "util/region-allocator.h"
|
||||||
#include "util/storage/slabhash.h"
|
#include "util/storage/slabhash.h"
|
||||||
#include "services/listen_dnsport.h"
|
#include "services/listen_dnsport.h"
|
||||||
#include "services/outside_network.h"
|
#include "services/outside_network.h"
|
||||||
|
#include "services/outbound_list.h"
|
||||||
#include "services/cache/rrset.h"
|
#include "services/cache/rrset.h"
|
||||||
#include "util/data/msgparse.h"
|
#include "util/data/msgparse.h"
|
||||||
|
|
||||||
|
|
@ -136,7 +138,7 @@ replyerror(int r, struct work_query* w)
|
||||||
/** process incoming request */
|
/** process incoming request */
|
||||||
static void
|
static void
|
||||||
worker_process_query(struct worker* worker, struct work_query* w,
|
worker_process_query(struct worker* worker, struct work_query* w,
|
||||||
enum module_ev event)
|
enum module_ev event, struct outbound_entry* entry)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
if(event == module_event_new) {
|
if(event == module_event_new) {
|
||||||
|
|
@ -146,7 +148,7 @@ worker_process_query(struct worker* worker, struct work_query* w,
|
||||||
}
|
}
|
||||||
/* allow current module to run */
|
/* allow current module to run */
|
||||||
(*worker->daemon->modfunc[w->state.curmod]->operate)(&w->state, event,
|
(*worker->daemon->modfunc[w->state.curmod]->operate)(&w->state, event,
|
||||||
w->state.curmod);
|
w->state.curmod, entry);
|
||||||
/* TODO examine results, start further modules, etc.
|
/* TODO examine results, start further modules, etc.
|
||||||
* assume it went to sleep
|
* assume it went to sleep
|
||||||
*/
|
*/
|
||||||
|
|
@ -178,7 +180,7 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||||
|
|
||||||
w->state.reply = reply_info;
|
w->state.reply = reply_info;
|
||||||
if(error != 0) {
|
if(error != 0) {
|
||||||
worker_process_query(worker, w, module_event_timeout);
|
worker_process_query(worker, w, module_event_timeout, NULL);
|
||||||
w->state.reply = NULL;
|
w->state.reply = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -189,11 +191,42 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||||
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
|
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
|
||||||
/* error becomes timeout for the module as if this reply
|
/* error becomes timeout for the module as if this reply
|
||||||
* never arrived. */
|
* never arrived. */
|
||||||
worker_process_query(worker, w, module_event_timeout);
|
worker_process_query(worker, w, module_event_timeout, NULL);
|
||||||
w->state.reply = NULL;
|
w->state.reply = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
worker_process_query(worker, w, module_event_reply);
|
worker_process_query(worker, w, module_event_reply, NULL);
|
||||||
|
w->state.reply = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** process incoming serviced query replies from the network */
|
||||||
|
static int
|
||||||
|
worker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||||
|
struct comm_reply* reply_info)
|
||||||
|
{
|
||||||
|
struct outbound_entry* e = (struct outbound_entry*)arg;
|
||||||
|
struct work_query* w = e->qstate->work_info;
|
||||||
|
struct worker* worker = w->state.env->worker;
|
||||||
|
|
||||||
|
w->state.reply = reply_info;
|
||||||
|
if(error != 0) {
|
||||||
|
worker_process_query(worker, w, module_event_timeout, e);
|
||||||
|
w->state.reply = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* sanity check. */
|
||||||
|
if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer))
|
||||||
|
|| LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) !=
|
||||||
|
LDNS_PACKET_QUERY
|
||||||
|
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
|
||||||
|
/* error becomes timeout for the module as if this reply
|
||||||
|
* never arrived. */
|
||||||
|
worker_process_query(worker, w, module_event_timeout, e);
|
||||||
|
w->state.reply = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
worker_process_query(worker, w, module_event_reply, e);
|
||||||
w->state.reply = NULL;
|
w->state.reply = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -444,7 +477,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||||
|
|
||||||
/* answer it */
|
/* answer it */
|
||||||
w->state.buf = c->buffer;
|
w->state.buf = c->buffer;
|
||||||
worker_process_query(worker, w, module_event_new);
|
worker_process_query(worker, w, module_event_new, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -688,7 +721,7 @@ worker_delete(struct worker* worker)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
worker_send_query(ldns_buffer* pkt, struct sockaddr_storage* addr,
|
worker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
|
||||||
socklen_t addrlen, int timeout, struct module_qstate* q, int use_tcp)
|
socklen_t addrlen, int timeout, struct module_qstate* q, int use_tcp)
|
||||||
{
|
{
|
||||||
struct worker* worker = q->env->worker;
|
struct worker* worker = q->env->worker;
|
||||||
|
|
@ -700,3 +733,24 @@ worker_send_query(ldns_buffer* pkt, struct sockaddr_storage* addr,
|
||||||
return pending_udp_query(worker->back, pkt, addr, addrlen, timeout,
|
return pending_udp_query(worker->back, pkt, addr, addrlen, timeout,
|
||||||
worker_handle_reply, q->work_info, worker->rndstate) != 0;
|
worker_handle_reply, q->work_info, worker->rndstate) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct outbound_entry*
|
||||||
|
worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||||
|
uint16_t qclass, uint16_t flags, int dnssec,
|
||||||
|
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||||
|
struct module_qstate* q)
|
||||||
|
{
|
||||||
|
struct worker* worker = q->env->worker;
|
||||||
|
struct outbound_entry* e = (struct outbound_entry*)malloc(sizeof(*e));
|
||||||
|
if(!e)
|
||||||
|
return NULL;
|
||||||
|
e->qstate = q;
|
||||||
|
e->qsent = outnet_serviced_query(worker->back, qname,
|
||||||
|
qnamelen, qtype, qclass, flags, dnssec, addr, addrlen,
|
||||||
|
worker_handle_service_reply, e, worker->back->udp_buff);
|
||||||
|
if(!e->qsent) {
|
||||||
|
free(e);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -188,10 +188,29 @@ void worker_sighandler(int sig, void* arg);
|
||||||
* @param timeout: seconds to wait until timeout.
|
* @param timeout: seconds to wait until timeout.
|
||||||
* @param q: wich query state to reactivate upon return.
|
* @param q: wich query state to reactivate upon return.
|
||||||
* @param use_tcp: true to use TCP, false for UDP.
|
* @param use_tcp: true to use TCP, false for UDP.
|
||||||
* return: false on failure (memory or socket related). no query was
|
* @return: false on failure (memory or socket related). no query was
|
||||||
* sent.
|
* sent.
|
||||||
*/
|
*/
|
||||||
int worker_send_query(ldns_buffer* pkt, struct sockaddr_storage* addr,
|
int worker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
|
||||||
socklen_t addrlen, int timeout, struct module_qstate* q, int use_tcp);
|
socklen_t addrlen, int timeout, struct module_qstate* q, int use_tcp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Worker service routine to send serviced queries to authoritative servers.
|
||||||
|
* @param qname: query name. (host order)
|
||||||
|
* @param qnamelen: length in bytes of qname, including trailing 0.
|
||||||
|
* @param qtype: query type. (host order)
|
||||||
|
* @param qclass: query class. (host order)
|
||||||
|
* @param flags: host order flags word, with opcode and CD bit.
|
||||||
|
* @param dnssec: if set, EDNS record will have DO bit set.
|
||||||
|
* @param addr: where to.
|
||||||
|
* @param addrlen: length of addr.
|
||||||
|
* @param q: wich query state to reactivate upon return.
|
||||||
|
* @return: false on failure (memory or socket related). no query was
|
||||||
|
* sent.
|
||||||
|
*/
|
||||||
|
struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen,
|
||||||
|
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
|
||||||
|
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||||
|
struct module_qstate* q);
|
||||||
|
|
||||||
#endif /* DAEMON_WORKER_H */
|
#endif /* DAEMON_WORKER_H */
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
22 May 2007: Wouter
|
||||||
|
- outbound query list for modules and support to callback with the
|
||||||
|
outbound entry to the module.
|
||||||
|
- testbound support for new serviced queries.
|
||||||
|
- test for retry to TCP cannot use testbound any longer.
|
||||||
|
|
||||||
21 May 2007: Wouter
|
21 May 2007: Wouter
|
||||||
- small comment on hash table locking.
|
- small comment on hash table locking.
|
||||||
- outside network serviced queries, contain edns and tcp fallback,
|
- outside network serviced queries, contain edns and tcp fallback,
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
#include "util/config_file.h"
|
#include "util/config_file.h"
|
||||||
#include "util/net_help.h"
|
#include "util/net_help.h"
|
||||||
#include "util/storage/slabhash.h"
|
#include "util/storage/slabhash.h"
|
||||||
|
#include "util/region-allocator.h"
|
||||||
#include "services/cache/rrset.h"
|
#include "services/cache/rrset.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -162,74 +163,87 @@ store_msg(struct module_qstate* qstate, struct query_info* qinfo,
|
||||||
&e->entry, rep, &qstate->env->alloc);
|
&e->entry, rep, &qstate->env->alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** iterator operate on a query */
|
/** new query for iterator */
|
||||||
static void
|
static int
|
||||||
iter_operate(struct module_qstate* qstate, enum module_ev event, int id)
|
iter_new(struct module_qstate* qstate, int id)
|
||||||
{
|
{
|
||||||
|
struct iter_qstate* iq = (struct iter_qstate*)region_alloc(
|
||||||
|
qstate->region, sizeof(struct iter_qstate));
|
||||||
struct module_env* env = qstate->env;
|
struct module_env* env = qstate->env;
|
||||||
struct iter_env* ie = (struct iter_env*)env->modinfo[id];
|
struct iter_env* ie = (struct iter_env*)env->modinfo[id];
|
||||||
|
struct outbound_entry* e;
|
||||||
|
uint16_t flags = 0; /* opcode=query, no flags */
|
||||||
|
int dnssec = 1; /* always get dnssec info */
|
||||||
|
qstate->minfo[id] = iq;
|
||||||
|
if(!iq)
|
||||||
|
return 0;
|
||||||
|
outbound_list_init(&iq->outlist);
|
||||||
|
if(qstate->qinfo.has_cd)
|
||||||
|
flags |= BIT_CD;
|
||||||
|
e = (*env->send_query)(qstate->qinfo.qname, qstate->qinfo.qnamesize,
|
||||||
|
qstate->qinfo.qtype, qstate->qinfo.qclass, flags, dnssec,
|
||||||
|
&ie->fwd_addr, ie->fwd_addrlen, qstate);
|
||||||
|
if(!e)
|
||||||
|
return 0;
|
||||||
|
outbound_list_insert(&iq->outlist, e);
|
||||||
|
qstate->ext_state[id] = module_wait_reply;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** iterator handle reply from authoritative server */
|
||||||
|
static int
|
||||||
|
iter_handlereply(struct module_qstate* qstate, int id,
|
||||||
|
struct outbound_entry* ATTR_UNUSED(outbound))
|
||||||
|
{
|
||||||
|
struct module_env* env = qstate->env;
|
||||||
|
uint16_t us = qstate->edns.udp_size;
|
||||||
|
struct query_info reply_qinfo;
|
||||||
|
struct reply_info* reply_msg;
|
||||||
|
struct edns_data reply_edns;
|
||||||
|
int r;
|
||||||
|
if((r=reply_info_parse(qstate->reply->c->buffer, env->alloc,
|
||||||
|
&reply_qinfo, &reply_msg, qstate->scratch,
|
||||||
|
&reply_edns))!=0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
qstate->edns.edns_version = EDNS_ADVERTISED_VERSION;
|
||||||
|
qstate->edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
|
qstate->edns.ext_rcode = 0;
|
||||||
|
qstate->edns.bits &= EDNS_DO;
|
||||||
|
if(!reply_info_answer_encode(&reply_qinfo, reply_msg, 0,
|
||||||
|
qstate->query_flags, qstate->buf, 0, 0,
|
||||||
|
qstate->scratch, us, &qstate->edns))
|
||||||
|
return 0;
|
||||||
|
store_msg(qstate, &reply_qinfo, reply_msg);
|
||||||
|
qstate->ext_state[id] = module_finished;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** iterator operate on a query */
|
||||||
|
static void
|
||||||
|
iter_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||||
|
struct outbound_entry* outbound)
|
||||||
|
{
|
||||||
verbose(VERB_ALGO, "iterator[module %d] operate: extstate:%s event:%s",
|
verbose(VERB_ALGO, "iterator[module %d] operate: extstate:%s event:%s",
|
||||||
id, strextstate(qstate->ext_state[id]), strmodulevent(event));
|
id, strextstate(qstate->ext_state[id]), strmodulevent(event));
|
||||||
if(event == module_event_error) {
|
if(event == module_event_new) {
|
||||||
|
if(!iter_new(qstate, id))
|
||||||
|
qstate->ext_state[id] = module_error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* it must be a query reply */
|
||||||
|
if(!outbound) {
|
||||||
|
verbose(VERB_ALGO, "query reply was not serviced");
|
||||||
qstate->ext_state[id] = module_error;
|
qstate->ext_state[id] = module_error;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(event == module_event_new) {
|
if(event == module_event_timeout || event == module_event_error) {
|
||||||
/* send UDP query to forwarder address */
|
|
||||||
(*env->send_query)(qstate->buf, &ie->fwd_addr,
|
|
||||||
ie->fwd_addrlen, UDP_QUERY_TIMEOUT, qstate, 0);
|
|
||||||
qstate->ext_state[id] = module_wait_reply;
|
|
||||||
qstate->minfo[id] = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(event == module_event_timeout) {
|
|
||||||
/* try TCP if UDP fails */
|
|
||||||
/* TODO: disabled now, make better retry with EDNS.
|
|
||||||
if(qstate->reply->c->type == comm_udp) {
|
|
||||||
qinfo_query_encode(qstate->buf, &qstate->qinfo);
|
|
||||||
(*env->send_query)(qstate->buf, &ie->fwd_addr,
|
|
||||||
ie->fwd_addrlen, TCP_QUERY_TIMEOUT, qstate, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
qstate->ext_state[id] = module_error;
|
qstate->ext_state[id] = module_error;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(event == module_event_reply) {
|
if(event == module_event_reply) {
|
||||||
uint16_t us = qstate->edns.udp_size;
|
if(!iter_handlereply(qstate, id, outbound))
|
||||||
struct query_info reply_qinfo;
|
|
||||||
struct reply_info* reply_msg;
|
|
||||||
struct edns_data reply_edns;
|
|
||||||
int r;
|
|
||||||
/* see if it is truncated */
|
|
||||||
if(LDNS_TC_WIRE(ldns_buffer_begin(qstate->reply->c->buffer))
|
|
||||||
&& qstate->reply->c->type == comm_udp) {
|
|
||||||
log_info("TC: truncated. retry in TCP mode.");
|
|
||||||
qinfo_query_encode(qstate->buf, &qstate->qinfo);
|
|
||||||
(*env->send_query)(qstate->buf, &ie->fwd_addr,
|
|
||||||
ie->fwd_addrlen, TCP_QUERY_TIMEOUT, qstate, 1);
|
|
||||||
/* stay in wait_reply state */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if((r=reply_info_parse(qstate->reply->c->buffer, env->alloc,
|
|
||||||
&reply_qinfo, &reply_msg, qstate->scratch,
|
|
||||||
&reply_edns))!=0) {
|
|
||||||
qstate->ext_state[id] = module_error;
|
qstate->ext_state[id] = module_error;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qstate->edns.edns_version = EDNS_ADVERTISED_VERSION;
|
|
||||||
qstate->edns.udp_size = EDNS_ADVERTISED_SIZE;
|
|
||||||
qstate->edns.ext_rcode = 0;
|
|
||||||
qstate->edns.bits &= EDNS_DO;
|
|
||||||
if(!reply_info_answer_encode(&reply_qinfo, reply_msg, 0,
|
|
||||||
qstate->query_flags, qstate->buf, 0, 0,
|
|
||||||
qstate->scratch, us, &qstate->edns)) {
|
|
||||||
qstate->ext_state[id] = module_error;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
store_msg(qstate, &reply_qinfo, reply_msg);
|
|
||||||
qstate->ext_state[id] = module_finished;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log_err("bad event for iterator");
|
log_err("bad event for iterator");
|
||||||
|
|
@ -240,9 +254,11 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id)
|
||||||
static void
|
static void
|
||||||
iter_clear(struct module_qstate* qstate, int id)
|
iter_clear(struct module_qstate* qstate, int id)
|
||||||
{
|
{
|
||||||
|
struct iter_qstate* iq;
|
||||||
if(!qstate)
|
if(!qstate)
|
||||||
return;
|
return;
|
||||||
/* allocated in region, so nothing to do */
|
iq = (struct iter_qstate*)qstate->minfo[id];
|
||||||
|
outbound_list_clear(&iq->outlist);
|
||||||
qstate->minfo[id] = NULL;
|
qstate->minfo[id] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
#ifndef ITERATOR_ITERATOR_H
|
#ifndef ITERATOR_ITERATOR_H
|
||||||
#define ITERATOR_ITERATOR_H
|
#define ITERATOR_ITERATOR_H
|
||||||
|
#include "services/outbound_list.h"
|
||||||
struct module_func_block;
|
struct module_func_block;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -58,6 +59,8 @@ struct iter_env {
|
||||||
* Per query state for the iterator module.
|
* Per query state for the iterator module.
|
||||||
*/
|
*/
|
||||||
struct iter_qstate {
|
struct iter_qstate {
|
||||||
|
/** list of pending queries to authoritative servers. */
|
||||||
|
struct outbound_list outlist;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
86
services/outbound_list.c
Normal file
86
services/outbound_list.c
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* services/outbound_list.c - keep list of outbound serviced queries.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is open source.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||||
|
* be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "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 REGENTS OR CONTRIBUTORS 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* This file contains functions to help a module keep track of the
|
||||||
|
* queries it has outstanding to authoritative servers.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "services/outbound_list.h"
|
||||||
|
#include "services/outside_network.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
outbound_list_init(struct outbound_list* list)
|
||||||
|
{
|
||||||
|
list->first = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
outbound_list_clear(struct outbound_list* list)
|
||||||
|
{
|
||||||
|
struct outbound_entry *p, *np;
|
||||||
|
p = list->first;
|
||||||
|
while(p) {
|
||||||
|
np = p->next;
|
||||||
|
outnet_serviced_query_stop(p->qsent, p);
|
||||||
|
free(p);
|
||||||
|
p = np;
|
||||||
|
}
|
||||||
|
outbound_list_init(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
outbound_list_insert(struct outbound_list* list, struct outbound_entry* e)
|
||||||
|
{
|
||||||
|
e->next = list->first;
|
||||||
|
e->prev = NULL;
|
||||||
|
list->first = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
outbound_list_remove(struct outbound_list* list, struct outbound_entry* e)
|
||||||
|
{
|
||||||
|
if(!e)
|
||||||
|
return;
|
||||||
|
outnet_serviced_query_stop(e->qsent, e);
|
||||||
|
if(e->next)
|
||||||
|
e->next->prev = e->prev;
|
||||||
|
if(e->prev)
|
||||||
|
e->prev->next = e->next;
|
||||||
|
else list->first = e->next;
|
||||||
|
free(e);
|
||||||
|
}
|
||||||
105
services/outbound_list.h
Normal file
105
services/outbound_list.h
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* services/outbound_list.h - keep list of outbound serviced queries.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is open source.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||||
|
* be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "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 REGENTS OR CONTRIBUTORS 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* This file contains functions to help a module keep track of the
|
||||||
|
* queries it has outstanding to authoritative servers.
|
||||||
|
*/
|
||||||
|
#ifndef SERVICES_OUTBOUND_LIST_H
|
||||||
|
#define SERVICES_OUTBOUND_LIST_H
|
||||||
|
struct outbound_entry;
|
||||||
|
struct serviced_query;
|
||||||
|
struct module_qstate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The outbound list. This structure is part of the module specific query
|
||||||
|
* state.
|
||||||
|
*/
|
||||||
|
struct outbound_list {
|
||||||
|
/** The linked list of outbound query entries. */
|
||||||
|
struct outbound_entry* first;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outbound list entry. A serviced query sent by a module processing the
|
||||||
|
* query from the qstate. Double linked list to aid removal.
|
||||||
|
*/
|
||||||
|
struct outbound_entry {
|
||||||
|
/** next in list */
|
||||||
|
struct outbound_entry* next;
|
||||||
|
/** prev in list */
|
||||||
|
struct outbound_entry* prev;
|
||||||
|
/** The query that was sent out */
|
||||||
|
struct serviced_query* qsent;
|
||||||
|
/** the module query state that sent it */
|
||||||
|
struct module_qstate* qstate;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init the user allocated outbound list structure
|
||||||
|
* @param list: the list structure.
|
||||||
|
*/
|
||||||
|
void outbound_list_init(struct outbound_list* list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the user owner outbound list structure.
|
||||||
|
* Deletes serviced queries.
|
||||||
|
* @param list: the list structure. It is cleared, but the list struct itself
|
||||||
|
* is callers responsability to delete.
|
||||||
|
*/
|
||||||
|
void outbound_list_clear(struct outbound_list* list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert new entry into the list. Caller must allocate the entry with malloc.
|
||||||
|
* qstate and qsent are set by caller.
|
||||||
|
* @param list: the list to add to.
|
||||||
|
* @param e: entry to add, it is only half initialised at call start, fully
|
||||||
|
* initialised at call end.
|
||||||
|
*/
|
||||||
|
void outbound_list_insert(struct outbound_list* list,
|
||||||
|
struct outbound_entry* e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an entry from the list, and deletes it.
|
||||||
|
* Deletes serviced query in the entry.
|
||||||
|
* @param list: the list to remove from.
|
||||||
|
* @param e: the entry to remove.
|
||||||
|
*/
|
||||||
|
void outbound_list_remove(struct outbound_list* list,
|
||||||
|
struct outbound_entry* e);
|
||||||
|
|
||||||
|
#endif /* SERVICES_OUTBOUND_LIST_H */
|
||||||
|
|
@ -953,6 +953,7 @@ serviced_encode(struct serviced_query* sq, ldns_buffer* buff, int with_edns)
|
||||||
ldns_buffer_clear(buff);
|
ldns_buffer_clear(buff);
|
||||||
ldns_buffer_write_u16(buff, 0); /* id placeholder */
|
ldns_buffer_write_u16(buff, 0); /* id placeholder */
|
||||||
ldns_buffer_write(buff, sq->qbuf, sq->qbuflen);
|
ldns_buffer_write(buff, sq->qbuf, sq->qbuflen);
|
||||||
|
ldns_buffer_flip(buff);
|
||||||
if(with_edns) {
|
if(with_edns) {
|
||||||
/* add edns section */
|
/* add edns section */
|
||||||
struct edns_data edns;
|
struct edns_data edns;
|
||||||
|
|
@ -965,7 +966,6 @@ serviced_encode(struct serviced_query* sq, ldns_buffer* buff, int with_edns)
|
||||||
edns.bits = EDNS_DO;
|
edns.bits = EDNS_DO;
|
||||||
attach_edns_record(buff, &edns);
|
attach_edns_record(buff, &edns);
|
||||||
}
|
}
|
||||||
ldns_buffer_flip(buff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1002,11 +1002,12 @@ serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff)
|
||||||
|
|
||||||
/** call the callbacks for a serviced query */
|
/** call the callbacks for a serviced query */
|
||||||
static void
|
static void
|
||||||
serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c)
|
serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
|
||||||
|
struct comm_reply* rep)
|
||||||
{
|
{
|
||||||
struct service_callback* p = sq->cblist;
|
struct service_callback* p = sq->cblist;
|
||||||
while(p) {
|
while(p) {
|
||||||
(void)(*p->cb)(c, p->cb_arg, error, NULL);
|
(void)(*p->cb)(c, p->cb_arg, error, rep);
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1014,7 +1015,7 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c)
|
||||||
/** TCP reply or error callback for serviced queries */
|
/** TCP reply or error callback for serviced queries */
|
||||||
static int
|
static int
|
||||||
serviced_tcp_callback(struct comm_point* c, void* arg, int error,
|
serviced_tcp_callback(struct comm_point* c, void* arg, int error,
|
||||||
struct comm_reply* ATTR_UNUSED(rep))
|
struct comm_reply* rep)
|
||||||
{
|
{
|
||||||
struct serviced_query* sq = (struct serviced_query*)arg;
|
struct serviced_query* sq = (struct serviced_query*)arg;
|
||||||
sq->pending = NULL; /* removed after this callback */
|
sq->pending = NULL; /* removed after this callback */
|
||||||
|
|
@ -1030,7 +1031,7 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)rbtree_delete(sq->outnet->serviced, sq);
|
(void)rbtree_delete(sq->outnet->serviced, sq);
|
||||||
serviced_callbacks(sq, error, c);
|
serviced_callbacks(sq, error, c, rep);
|
||||||
serviced_delete(sq);
|
serviced_delete(sq);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1048,14 +1049,14 @@ serviced_tcp_initiate(struct outside_network* outnet,
|
||||||
* clash with this entry */
|
* clash with this entry */
|
||||||
log_err("serviced_tcp_initiate: failed to send tcp query");
|
log_err("serviced_tcp_initiate: failed to send tcp query");
|
||||||
(void)rbtree_delete(outnet->serviced, sq);
|
(void)rbtree_delete(outnet->serviced, sq);
|
||||||
serviced_callbacks(sq, NETEVENT_CLOSED, NULL);
|
serviced_callbacks(sq, NETEVENT_CLOSED, NULL, NULL);
|
||||||
serviced_delete(sq);
|
serviced_delete(sq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||||
struct comm_reply* ATTR_UNUSED(rep))
|
struct comm_reply* rep)
|
||||||
{
|
{
|
||||||
struct serviced_query* sq = (struct serviced_query*)arg;
|
struct serviced_query* sq = (struct serviced_query*)arg;
|
||||||
struct outside_network* outnet = sq->outnet;
|
struct outside_network* outnet = sq->outnet;
|
||||||
|
|
@ -1070,7 +1071,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||||
if(sq->retry < OUTBOUND_UDP_RETRY) {
|
if(sq->retry < OUTBOUND_UDP_RETRY) {
|
||||||
if(!serviced_udp_send(sq, c->buffer)) {
|
if(!serviced_udp_send(sq, c->buffer)) {
|
||||||
(void)rbtree_delete(outnet->serviced, sq);
|
(void)rbtree_delete(outnet->serviced, sq);
|
||||||
serviced_callbacks(sq, NETEVENT_CLOSED, c);
|
serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
|
||||||
serviced_delete(sq);
|
serviced_delete(sq);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1090,7 +1091,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||||
sq->retry = 0;
|
sq->retry = 0;
|
||||||
if(!serviced_udp_send(sq, c->buffer)) {
|
if(!serviced_udp_send(sq, c->buffer)) {
|
||||||
(void)rbtree_delete(outnet->serviced, sq);
|
(void)rbtree_delete(outnet->serviced, sq);
|
||||||
serviced_callbacks(sq, NETEVENT_CLOSED, c);
|
serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
|
||||||
serviced_delete(sq);
|
serviced_delete(sq);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1112,7 +1113,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||||
roundtime*1000, now))
|
roundtime*1000, now))
|
||||||
log_err("out of memory noting rtt.");
|
log_err("out of memory noting rtt.");
|
||||||
(void)rbtree_delete(outnet->serviced, sq);
|
(void)rbtree_delete(outnet->serviced, sq);
|
||||||
serviced_callbacks(sq, error, c);
|
serviced_callbacks(sq, error, c, rep);
|
||||||
serviced_delete(sq);
|
serviced_delete(sq);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1175,7 +1176,7 @@ void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg)
|
||||||
return;
|
return;
|
||||||
callback_list_remove(sq, cb_arg);
|
callback_list_remove(sq, cb_arg);
|
||||||
if(!sq->cblist) {
|
if(!sq->cblist) {
|
||||||
(void)rbtree_delete(sq->outnet->serviced, sq);
|
if(rbtree_delete(sq->outnet->serviced, sq))
|
||||||
serviced_delete(sq);
|
serviced_delete(sq); /* safe against double delete */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@
|
||||||
#include "testcode/fake_event.h"
|
#include "testcode/fake_event.h"
|
||||||
#include "util/netevent.h"
|
#include "util/netevent.h"
|
||||||
#include "util/net_help.h"
|
#include "util/net_help.h"
|
||||||
|
#include "util/data/msgparse.h"
|
||||||
|
#include "util/data/msgreply.h"
|
||||||
#include "services/listen_dnsport.h"
|
#include "services/listen_dnsport.h"
|
||||||
#include "services/outside_network.h"
|
#include "services/outside_network.h"
|
||||||
#include "testcode/replay.h"
|
#include "testcode/replay.h"
|
||||||
|
|
@ -688,6 +690,7 @@ pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||||
pend->timeout = timeout;
|
pend->timeout = timeout;
|
||||||
pend->transport = transport_udp;
|
pend->transport = transport_udp;
|
||||||
pend->pkt = NULL;
|
pend->pkt = NULL;
|
||||||
|
pend->runtime = runtime;
|
||||||
status = ldns_buffer2pkt_wire(&pend->pkt, packet);
|
status = ldns_buffer2pkt_wire(&pend->pkt, packet);
|
||||||
if(status != LDNS_STATUS_OK) {
|
if(status != LDNS_STATUS_OK) {
|
||||||
log_err("ldns error parsing udp output packet: %s",
|
log_err("ldns error parsing udp output packet: %s",
|
||||||
|
|
@ -736,6 +739,7 @@ pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||||
pend->timeout = timeout;
|
pend->timeout = timeout;
|
||||||
pend->transport = transport_tcp;
|
pend->transport = transport_tcp;
|
||||||
pend->pkt = NULL;
|
pend->pkt = NULL;
|
||||||
|
pend->runtime = runtime;
|
||||||
status = ldns_buffer2pkt_wire(&pend->pkt, packet);
|
status = ldns_buffer2pkt_wire(&pend->pkt, packet);
|
||||||
if(status != LDNS_STATUS_OK) {
|
if(status != LDNS_STATUS_OK) {
|
||||||
log_err("ldns error parsing tcp output packet: %s",
|
log_err("ldns error parsing tcp output packet: %s",
|
||||||
|
|
@ -761,6 +765,100 @@ pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||||
return (struct waiting_tcp*)pend;
|
return (struct waiting_tcp*)pend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
|
||||||
|
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||||
|
uint16_t flags, int dnssec, struct sockaddr_storage* addr,
|
||||||
|
socklen_t addrlen, comm_point_callback_t* callback,
|
||||||
|
void* callback_arg, ldns_buffer* ATTR_UNUSED(buff))
|
||||||
|
{
|
||||||
|
struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
|
||||||
|
struct fake_pending* pend = (struct fake_pending*)calloc(1,
|
||||||
|
sizeof(struct fake_pending));
|
||||||
|
ldns_status status;
|
||||||
|
log_assert(pend);
|
||||||
|
|
||||||
|
/* create packet with EDNS */
|
||||||
|
pend->buffer = ldns_buffer_new(512);
|
||||||
|
log_assert(pend->buffer);
|
||||||
|
ldns_buffer_write_u16(pend->buffer, 0); /* id */
|
||||||
|
ldns_buffer_write_u16(pend->buffer, flags);
|
||||||
|
ldns_buffer_write_u16(pend->buffer, 1); /* qdcount */
|
||||||
|
ldns_buffer_write_u16(pend->buffer, 0); /* ancount */
|
||||||
|
ldns_buffer_write_u16(pend->buffer, 0); /* nscount */
|
||||||
|
ldns_buffer_write_u16(pend->buffer, 0); /* arcount */
|
||||||
|
ldns_buffer_write(pend->buffer, qname, qnamelen);
|
||||||
|
ldns_buffer_write_u16(pend->buffer, qtype);
|
||||||
|
ldns_buffer_write_u16(pend->buffer, qclass);
|
||||||
|
ldns_buffer_flip(pend->buffer);
|
||||||
|
if(1) {
|
||||||
|
/* add edns */
|
||||||
|
struct edns_data edns;
|
||||||
|
edns.edns_present = 1;
|
||||||
|
edns.ext_rcode = 0;
|
||||||
|
edns.edns_version = EDNS_ADVERTISED_VERSION;
|
||||||
|
edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
|
edns.bits = 0;
|
||||||
|
if(dnssec)
|
||||||
|
edns.bits = EDNS_DO;
|
||||||
|
attach_edns_record(pend->buffer, &edns);
|
||||||
|
}
|
||||||
|
memcpy(&pend->addr, addr, addrlen);
|
||||||
|
pend->addrlen = addrlen;
|
||||||
|
pend->callback = callback;
|
||||||
|
pend->cb_arg = callback_arg;
|
||||||
|
pend->timeout = UDP_QUERY_TIMEOUT;
|
||||||
|
pend->transport = transport_udp; /* pretend UDP */
|
||||||
|
pend->pkt = NULL;
|
||||||
|
pend->runtime = runtime;
|
||||||
|
status = ldns_buffer2pkt_wire(&pend->pkt, pend->buffer);
|
||||||
|
if(status != LDNS_STATUS_OK) {
|
||||||
|
log_err("ldns error parsing serviced output packet: %s",
|
||||||
|
ldns_get_errorstr_by_id(status));
|
||||||
|
fatal_exit("internal error");
|
||||||
|
}
|
||||||
|
log_pkt("pending serviced query: ", pend->pkt);
|
||||||
|
|
||||||
|
/* see if it matches the current moment */
|
||||||
|
if(runtime->now && runtime->now->evt_type == repevt_back_query &&
|
||||||
|
find_match(runtime->now->match, pend->pkt, pend->transport)) {
|
||||||
|
log_info("testbound: matched pending to event. "
|
||||||
|
"advance time between events.");
|
||||||
|
log_info("testbound: do STEP %d %s", runtime->now->time_step,
|
||||||
|
repevt_string(runtime->now->evt_type));
|
||||||
|
advance_moment(runtime);
|
||||||
|
/* still create the pending, because we need it to callback */
|
||||||
|
}
|
||||||
|
log_info("testbound: created fake pending");
|
||||||
|
/* add to list */
|
||||||
|
pend->next = runtime->pending_list;
|
||||||
|
runtime->pending_list = pend;
|
||||||
|
return (struct serviced_query*)pend;
|
||||||
|
}
|
||||||
|
|
||||||
|
void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg)
|
||||||
|
{
|
||||||
|
struct fake_pending* pend = (struct fake_pending*)sq;
|
||||||
|
struct replay_runtime* runtime = pend->runtime;
|
||||||
|
/* delete from the list */
|
||||||
|
struct fake_pending* p = runtime->pending_list, *prev=NULL;
|
||||||
|
while(p) {
|
||||||
|
if(p == pend) {
|
||||||
|
log_assert(p->cb_arg == cb_arg);
|
||||||
|
if(prev)
|
||||||
|
prev->next = p->next;
|
||||||
|
else runtime->pending_list = p->next;
|
||||||
|
log_pkt("deleted pending serviced query.", p->pkt);
|
||||||
|
ldns_buffer_free(p->buffer);
|
||||||
|
ldns_pkt_free(p->pkt);
|
||||||
|
free(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prev = p;
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
log_pkt("double delet of pending serviced query", p->pkt);
|
||||||
|
}
|
||||||
|
|
||||||
struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg))
|
struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg))
|
||||||
{
|
{
|
||||||
return calloc(1, 1);
|
return calloc(1, 1);
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,8 @@ struct fake_pending {
|
||||||
ldns_pkt* pkt;
|
ldns_pkt* pkt;
|
||||||
/** by what transport was the query sent out */
|
/** by what transport was the query sent out */
|
||||||
enum transport_type transport;
|
enum transport_type transport;
|
||||||
|
/** the runtime structure this is part of */
|
||||||
|
struct replay_runtime* runtime;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
69
testdata/fwd_trunc.rpl
vendored
69
testdata/fwd_trunc.rpl
vendored
|
|
@ -1,69 +0,0 @@
|
||||||
; This is a comment.
|
|
||||||
; config options go here.
|
|
||||||
CONFIG_END
|
|
||||||
|
|
||||||
SCENARIO_BEGIN Query forwarded, receives truncated reply.
|
|
||||||
|
|
||||||
STEP 1 QUERY
|
|
||||||
ENTRY_BEGIN
|
|
||||||
REPLY RD
|
|
||||||
SECTION QUESTION
|
|
||||||
www.example.com. IN A
|
|
||||||
ENTRY_END
|
|
||||||
; the query is sent to the forwarder - UDP
|
|
||||||
STEP 2 CHECK_OUT_QUERY
|
|
||||||
ENTRY_BEGIN
|
|
||||||
MATCH qname qtype opcode UDP
|
|
||||||
SECTION QUESTION
|
|
||||||
www.example.com. IN A
|
|
||||||
ENTRY_END
|
|
||||||
; reply TC bit
|
|
||||||
STEP 3 REPLY
|
|
||||||
ENTRY_BEGIN
|
|
||||||
MATCH opcode qtype qname UDP
|
|
||||||
ADJUST copy_id
|
|
||||||
; authoritative answer
|
|
||||||
REPLY QR AA RD RA TC NOERROR
|
|
||||||
SECTION QUESTION
|
|
||||||
www.example.com. IN A
|
|
||||||
SECTION ANSWER
|
|
||||||
www.example.com. IN A 10.20.30.40
|
|
||||||
ENTRY_END
|
|
||||||
; retry in TCP mode.
|
|
||||||
STEP 4 CHECK_OUT_QUERY
|
|
||||||
ENTRY_BEGIN
|
|
||||||
MATCH qname qtype opcode TCP
|
|
||||||
SECTION QUESTION
|
|
||||||
www.example.com. IN A
|
|
||||||
ENTRY_END
|
|
||||||
STEP 5 REPLY
|
|
||||||
ENTRY_BEGIN
|
|
||||||
MATCH opcode qtype qname TCP
|
|
||||||
ADJUST copy_id
|
|
||||||
; authoritative answer
|
|
||||||
REPLY QR AA RD RA NOERROR
|
|
||||||
SECTION QUESTION
|
|
||||||
www.example.com. IN A
|
|
||||||
SECTION ANSWER
|
|
||||||
www.example.com. IN A 10.20.30.40
|
|
||||||
SECTION AUTHORITY
|
|
||||||
www.example.com. IN NS ns.example.com.
|
|
||||||
SECTION ADDITIONAL
|
|
||||||
ns.example.com. IN A 10.20.30.50
|
|
||||||
ENTRY_END
|
|
||||||
STEP 6 CHECK_ANSWER
|
|
||||||
ENTRY_BEGIN
|
|
||||||
MATCH all
|
|
||||||
; first reply, have AA set.
|
|
||||||
REPLY QR AA RD RA
|
|
||||||
SECTION QUESTION
|
|
||||||
www.example.com. IN A
|
|
||||||
SECTION ANSWER
|
|
||||||
www.example.com. IN A 10.20.30.40
|
|
||||||
SECTION AUTHORITY
|
|
||||||
www.example.com. IN NS ns.example.com.
|
|
||||||
SECTION ADDITIONAL
|
|
||||||
ns.example.com. IN A 10.20.30.50
|
|
||||||
ENTRY_END
|
|
||||||
|
|
||||||
SCENARIO_END
|
|
||||||
|
|
@ -74,22 +74,48 @@ struct module_env {
|
||||||
|
|
||||||
/* --- services --- */
|
/* --- services --- */
|
||||||
/**
|
/**
|
||||||
|
* Direct access to the network, this packet gets sent to destination.
|
||||||
* Send DNS query to server. operate() should return with wait_reply.
|
* Send DNS query to server. operate() should return with wait_reply.
|
||||||
* Later on a callback will cause operate() to be called with event
|
* Later on a callback will cause operate() to be called with event
|
||||||
* timeout or reply.
|
* timeout or reply. Replied packet is then in the query buffer.
|
||||||
* @param pkt: packet to send.
|
* @param pkt: packet to send.
|
||||||
* @param addr: where to.
|
* @param addr: where to.
|
||||||
* @param addrlen: length of addr.
|
* @param addrlen: length of addr.
|
||||||
* @param timeout: seconds to wait until timeout.
|
* @param timeout: seconds to wait until timeout.
|
||||||
* @param q: wich query state to reactivate upon return.
|
* @param q: wich query state to reactivate upon return.
|
||||||
* @param use_tcp: set to true to send over TCP. 0 for UDP.
|
* @param use_tcp: set to true to send over TCP. 0 for UDP.
|
||||||
* return: false on failure (memory or socket related). no query was
|
* @return: false on failure (memory or socket related). no query was
|
||||||
* sent.
|
* sent.
|
||||||
*/
|
*/
|
||||||
int (*send_query)(ldns_buffer* pkt, struct sockaddr_storage* addr,
|
int (*send_packet)(ldns_buffer* pkt, struct sockaddr_storage* addr,
|
||||||
socklen_t addrlen, int timeout, struct module_qstate* q,
|
socklen_t addrlen, int timeout, struct module_qstate* q,
|
||||||
int use_tcp);
|
int use_tcp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send serviced DNS query to server. UDP/TCP and EDNS is handled.
|
||||||
|
* operate() should return with wait_reply. Later on a callback
|
||||||
|
* will cause operate() to be called with event timeout or reply.
|
||||||
|
* The time until a timeout is calculated from roundtrip timing,
|
||||||
|
* several UDP retries are attempted.
|
||||||
|
* @param qname: query name. (host order)
|
||||||
|
* @param qnamelen: length in bytes of qname, including trailing 0.
|
||||||
|
* @param qtype: query type. (host order)
|
||||||
|
* @param qclass: query class. (host order)
|
||||||
|
* @param flags: host order flags word, with opcode and CD bit.
|
||||||
|
* @param dnssec: if set, EDNS record will have DO bit set.
|
||||||
|
* @param addr: where to.
|
||||||
|
* @param addrlen: length of addr.
|
||||||
|
* @param q: wich query state to reactivate upon return.
|
||||||
|
* @return: false on failure (memory or socket related). no query was
|
||||||
|
* sent. Or returns an outbound entry with qsent and qstate set.
|
||||||
|
* This outbound_entry will be used on later module invocations
|
||||||
|
* that involve this query (timeout, error or reply).
|
||||||
|
*/
|
||||||
|
struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen,
|
||||||
|
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
|
||||||
|
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||||
|
struct module_qstate* q);
|
||||||
|
|
||||||
/** create a subquery. operate should then return with wait_subq */
|
/** create a subquery. operate should then return with wait_subq */
|
||||||
|
|
||||||
/** allocation service */
|
/** allocation service */
|
||||||
|
|
@ -210,6 +236,9 @@ struct module_func_block {
|
||||||
* @param ev: event that causes the module state machine to
|
* @param ev: event that causes the module state machine to
|
||||||
* (re-)activate.
|
* (re-)activate.
|
||||||
* @param qstate: the query state.
|
* @param qstate: the query state.
|
||||||
|
* @param id: module id number that operate() is called on.
|
||||||
|
* @param outbound: if not NULL this event is due to the reply/timeout
|
||||||
|
* or error on this outbound query.
|
||||||
* @return: if at exit the ext_state is:
|
* @return: if at exit the ext_state is:
|
||||||
* o wait_module: next module is started. (with pass event).
|
* o wait_module: next module is started. (with pass event).
|
||||||
* o error or finished: previous module is resumed.
|
* o error or finished: previous module is resumed.
|
||||||
|
|
@ -218,7 +247,7 @@ struct module_func_block {
|
||||||
* have been called.
|
* have been called.
|
||||||
*/
|
*/
|
||||||
void (*operate)(struct module_qstate* qstate, enum module_ev event,
|
void (*operate)(struct module_qstate* qstate, enum module_ev event,
|
||||||
int id);
|
int id, struct outbound_entry* outbound);
|
||||||
/**
|
/**
|
||||||
* clear module specific data
|
* clear module specific data
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue