edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL,
- msg->rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
+ msg->rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
+ *worker->env.now_tv))
return 0;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, msg->rep,
- (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
+ (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad,
+ *worker->env.now_tv))
return 0;
msg->rep->flags |= BIT_QR|BIT_RA;
if(!apply_edns_options(edns, &edns_bak, worker->env.cfg,
repinfo->c->buffer, 0, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
- LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
+ LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
+ *worker->env.now_tv))
edns->opt_list = NULL;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
- LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
+ LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
+ *worker->env.now_tv))
goto bail_out;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns);
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, rep,
- (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
+ (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad,
+ *worker->env.now_tv))
goto bail_out;
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
repinfo->c->buffer, timenow, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), *is_secure_answer)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
- LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
+ LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
+ *worker->env.now_tv))
edns->opt_list = NULL;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns);
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
- LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad))
+ LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
+ *worker->env.now_tv))
edns->opt_list = NULL;
if(sldns_buffer_capacity(pkt) >=
sldns_buffer_limit(pkt)+calc_edns_field_size(edns))
int dynlib_inplace_cb_reply_generic(struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
struct edns_data* edns, struct edns_option** opt_list_out,
- struct comm_reply* repinfo, struct regional* region, int id,
- void* callback) {
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time, int id, void* callback) {
struct cb_pair* cb_pair = (struct cb_pair*) callback;
- return ((inplace_cb_reply_func_type*) cb_pair->cb)(qinfo, qstate, rep, rcode, edns, opt_list_out, repinfo, region, id, cb_pair->cb_arg);
+ return ((inplace_cb_reply_func_type*) cb_pair->cb)(qinfo, qstate, rep, rcode, edns, opt_list_out, repinfo, region, start_time, id, cb_pair->cb_arg);
}
int dynlib_inplace_cb_query_generic(struct query_info* qinfo, uint16_t flags,
int dynlib_inplace_cb_reply_generic(struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
struct edns_data* edns, struct edns_option** opt_list_out,
- struct comm_reply* repinfo, struct regional* region, int id,
- void* callback);
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time, int id, void* callback);
int dynlib_inplace_cb_query_generic(struct query_info* qinfo, uint16_t flags,
struct module_qstate* qstate, struct sockaddr_storage* addr,
int reply_callback(struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
struct edns_data* edns, struct edns_option** opt_list_out,
- struct comm_reply* repinfo, struct regional* region, int id,
- void* callback);
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time, int id, void* callback);
/* Init is called when the module is first loaded. It should be used to set up
* the environment for this module and do any other initialisation required. */
int reply_callback(struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
struct edns_data* edns, struct edns_option** opt_list_out,
- struct comm_reply* repinfo, struct regional* region, int id,
- void* callback) {
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time, int id, void* callback) {
log_info("dynlib: hello world from callback");
struct dynlibmod_env* env = qstate->env->modinfo[id];
if (env->dyn_env != NULL) {
* called to perform operations on queries.
*/
#include <sys/types.h>
+ #include <time.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
/* ************************************************************************************ *
Structure module_env
* ************************************************************************************ */
+%rename(_now) module_env::now;
+%rename(_now_tv) module_env::now_tv;
struct module_env {
struct config_file* cfg;
struct slabhash* msg_cache;
size_t edns_known_options_num;
};
+%inline %{
+ PyObject* _module_env_now_get(struct module_env* env) {
+ double ts = env->now_tv->tv_sec + env->now_tv->tv_usec / 1e6;
+ return PyFloat_FromDouble(ts);
+ }
+%}
+%extend module_env {
+ %pythoncode %{
+ def _now_get(self): return _module_env_now_get(self)
+ now = property(_now_get)
+ %}
+}
+
/* ************************************************************************************ *
Structure module_qstate
* ************************************************************************************ */
int python_inplace_cb_reply_generic(struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
struct edns_data* edns, struct edns_option** opt_list_out,
- struct comm_reply* repinfo, struct regional* region, int id,
- void* python_callback)
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time, int id, void* python_callback)
{
PyObject *func, *py_edns, *py_qstate, *py_opt_list_out, *py_qinfo;
PyObject *py_rep, *py_repinfo, *py_region;
PyObject *py_args, *py_kwargs, *result;
int res = 0;
+ double py_start_time = start_time.tv_sec + start_time.tv_usec / 1e6;
PyGILState_STATE gstate = PyGILState_Ensure();
func = (PyObject *) python_callback;
py_region = SWIG_NewPointerObj((void*) region, SWIGTYPE_p_regional, 0);
py_args = Py_BuildValue("(OOOiOOO)", py_qinfo, py_qstate, py_rep,
rcode, py_edns, py_opt_list_out, py_region);
- py_kwargs = Py_BuildValue("{s:O}", "repinfo", py_repinfo);
+ py_kwargs = Py_BuildValue("{s:O,s:d}", "repinfo", py_repinfo, "start_time",
+ py_start_time);
result = PyObject_Call(func, py_args, py_kwargs);
Py_XDECREF(py_edns);
Py_XDECREF(py_qstate);
int python_inplace_cb_reply_generic(struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
struct edns_data* edns, struct edns_option** opt_list_out,
- struct comm_reply* repinfo, struct regional* region, int id,
- void* python_callback);
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time, int id, void* python_callback);
/** Declared here for fptr_wlist access. The definition is in interface.i. */
int python_inplace_cb_query_generic(
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, msg->rep,
- (int)FLAGS_GET_RCODE(msg->rep->flags), edns, repinfo, temp)
+ (int)FLAGS_GET_RCODE(msg->rep->flags), edns, repinfo, temp, *env->now_tv)
|| !reply_info_answer_encode(qinfo, msg->rep,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2),
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
- rcode, edns, repinfo, temp))
+ rcode, edns, repinfo, temp, *env->now_tv))
edns->opt_list = NULL;
error_encode(buf, rcode|BIT_AA, qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
- repinfo, temp) || !reply_info_answer_encode(qinfo, &rep,
+ repinfo, temp, *env->now_tv) || !reply_info_answer_encode(qinfo, &rep,
*(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
- rcode, edns, repinfo, temp))
+ rcode, edns, repinfo, temp, *env->now_tv))
edns->opt_list = NULL;
error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
if(!s) {
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
- LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
+ LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, *s->s.env->now_tv))
edns->opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
if(!s->s.edns_opts_front_in) {
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL,
- NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
+ NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, *s->s.env->now_tv))
edns->opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
servfail_mem:
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
- NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
+ NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, *s->s.env->now_tv))
edns->opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
*/
static void
mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
- struct mesh_cb* r)
+ struct mesh_cb* r, struct timeval start_time)
{
int secure;
char* reason = NULL;
if(rcode) {
if(rcode == LDNS_RCODE_SERVFAIL) {
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, rcode, &r->edns, NULL, m->s.region))
+ rep, rcode, &r->edns, NULL, m->s.region, start_time))
r->edns.opt_list = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
- &r->edns, NULL, m->s.region))
+ &r->edns, NULL, m->s.region, start_time))
r->edns.opt_list = NULL;
}
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
r->edns.bits &= EDNS_DO;
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
- LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region) ||
+ LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region, start_time) ||
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r->buf, 0, 1,
m->s.env->scratch, udp_size, &r->edns,
m->s.qinfo.local_alias = r->local_alias;
if(rcode == LDNS_RCODE_SERVFAIL) {
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, rcode, &r->edns, &r->query_reply, m->s.region))
+ rep, rcode, &r->edns, &r->query_reply, m->s.region, r->start_time))
r->edns.opt_list = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
- &r->edns, &r->query_reply, m->s.region))
+ &r->edns, &r->query_reply, m->s.region, r->start_time))
r->edns.opt_list = NULL;
}
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
m->s.qinfo.qname = r->qname;
m->s.qinfo.local_alias = r->local_alias;
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
- LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region) ||
+ LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region, r->start_time) ||
!apply_edns_options(&r->edns, &edns_bak,
m->s.env->cfg, r->query_reply.c,
m->s.region) ||
secure))
{
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region))
+ rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, r->start_time))
r->edns.opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
&m->s.qinfo, r->qid, r->qflags, &r->edns);
struct mesh_cb* c;
struct reply_info* rep = (mstate->s.return_msg?
mstate->s.return_msg->rep:NULL);
+ struct timeval tv = {0, 0};
/* No need for the serve expired timer anymore; we are going to reply. */
if(mstate->s.serve_expired_data) {
comm_timer_delete(mstate->s.serve_expired_data->timer);
}
}
for(r = mstate->reply_list; r; r = r->next) {
+ tv = r->start_time;
+
/* if a response-ip address block has been stored the
* information should be logged for each client. */
if(mstate->s.respip_action_info &&
if(!mstate->reply_list && !mstate->cb_list &&
mstate->super_set.count == 0)
mstate->s.env->mesh->num_detached_states++;
- mesh_do_callback(mstate, mstate->s.return_rcode, rep, c);
+ mesh_do_callback(mstate, mstate->s.return_rcode, rep, c, tv);
}
}
struct respip_action_info actinfo;
struct query_info* lookup_qinfo = &qstate->qinfo;
struct query_info qinfo_tmp;
+ struct timeval tv = {0, 0};
int must_validate = (!(qstate->query_flags&BIT_CD)
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
if(!qstate->serve_expired_data) return;
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
for(r = mstate->reply_list; r; r = r->next) {
+ tv = r->start_time;
+
/* If address info is returned, it means the action should be an
* 'inform' variant and the information should be logged. */
if(actinfo.addrinfo) {
if(!mstate->reply_list && !mstate->cb_list &&
mstate->super_set.count == 0)
qstate->env->mesh->num_detached_states++;
- mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c);
+ mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c, tv);
}
}
struct inplace_cb* callback_list, enum inplace_cb_list_type type,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct comm_reply* repinfo, struct regional* region)
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time)
{
struct inplace_cb* cb;
struct edns_option* opt_list_out = NULL;
fptr_ok(fptr_whitelist_inplace_cb_reply_generic(
(inplace_cb_reply_func_type*)cb->cb, type));
(void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep,
- rcode, edns, &opt_list_out, repinfo, region, cb->id, cb->cb_arg);
+ rcode, edns, &opt_list_out, repinfo, region, start_time, cb->id, cb->cb_arg);
}
edns->opt_list = opt_list_out;
return 1;
int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
- struct edns_data* edns, struct comm_reply* repinfo, struct regional* region)
+ struct edns_data* edns, struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time)
{
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo,
- qstate, rep, rcode, edns, repinfo, region);
+ qstate, rep, rcode, edns, repinfo, region, start_time);
}
int inplace_cb_reply_cache_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct comm_reply* repinfo, struct regional* region)
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time)
{
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache,
- qinfo, qstate, rep, rcode, edns, repinfo, region);
+ qinfo, qstate, rep, rcode, edns, repinfo, region, start_time);
}
int inplace_cb_reply_local_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct comm_reply* repinfo, struct regional* region)
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time)
{
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local,
- qinfo, qstate, rep, rcode, edns, repinfo, region);
+ qinfo, qstate, rep, rcode, edns, repinfo, region, start_time);
}
int inplace_cb_reply_servfail_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct comm_reply* repinfo, struct regional* region)
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time)
{
/* We are going to servfail. Remove any potential edns options. */
if(qstate)
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply_servfail],
inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, repinfo,
- region);
+ region, start_time);
}
int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
*/
int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
- struct edns_data* edns, struct comm_reply* repinfo, struct regional* region);
+ struct edns_data* edns, struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time);
/**
* Call the registered functions in the inplace_cb_reply_cache linked list.
int inplace_cb_reply_cache_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct comm_reply* repinfo, struct regional* region);
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time);
/**
* Call the registered functions in the inplace_cb_reply_local linked list.
int inplace_cb_reply_local_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct comm_reply* repinfo, struct regional* region);
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time);
/**
* Call the registered functions in the inplace_cb_reply linked list.
int inplace_cb_reply_servfail_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct comm_reply* repinfo, struct regional* region);
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time);
/**
* Call the registered functions in the inplace_cb_query linked list.
typedef int inplace_cb_reply_func_type(struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
struct edns_data* edns, struct edns_option** opt_list_out,
- struct comm_reply* repinfo, struct regional* region, int id,
- void* callback);
+ struct comm_reply* repinfo, struct regional* region,
+ struct timeval start_time, int id, void* callback);
/**
* Inplace callback function called before sending the query to a nameserver.