edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL,
- msg->rep, LDNS_RCODE_SERVFAIL, edns, worker->scratchpad))
+ msg->rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
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, worker->scratchpad))
+ (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
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, worker->scratchpad))
+ LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
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, worker->scratchpad))
+ LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
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, worker->scratchpad))
+ (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
goto bail_out;
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
if(worker->daemon->use_response_ip && !partial_rep &&
repinfo->c->buffer, timenow, 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, worker->scratchpad))
+ LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
edns->opt_list = NULL;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns);
* @param num: number of strings in array.
* @param edns: edns reply information.
* @param worker: worker with scratch region.
+ * @param repinfo: reply information for a communication point.
*/
static void
chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
- struct worker* worker)
+ struct worker* worker, struct comm_reply* repinfo)
{
int i;
unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt));
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, worker->scratchpad))
+ LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad))
edns->opt_list = NULL;
if(sldns_buffer_capacity(pkt) >=
sldns_buffer_limit(pkt)+calc_edns_field_size(edns))
/** Reply with one string */
static void
chaos_replyonestr(sldns_buffer* pkt, const char* str, struct edns_data* edns,
- struct worker* worker)
+ struct worker* worker, struct comm_reply* repinfo)
{
- chaos_replystr(pkt, (char**)&str, 1, edns, worker);
+ chaos_replystr(pkt, (char**)&str, 1, edns, worker, repinfo);
}
/**
* @param pkt: buffer
* @param edns: edns reply information.
* @param w: worker with scratch region.
+ * @param repinfo: reply information for a communication point.
*/
static void
-chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w)
+chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w,
+ struct comm_reply* repinfo)
{
#define TA_RESPONSE_MAX_TXT 16 /* max number of TXT records */
#define TA_RESPONSE_MAX_TAGS 32 /* max number of tags printed per zone */
if(!w->env.need_to_validate) {
/* no validator module, reply no trustanchors */
- chaos_replystr(pkt, NULL, 0, edns, w);
+ chaos_replystr(pkt, NULL, 0, edns, w, repinfo);
return;
}
}
lock_basic_unlock(&w->env.anchors->lock);
- chaos_replystr(pkt, str_array, num, edns, w);
+ chaos_replystr(pkt, str_array, num, edns, w, repinfo);
regional_free_all(w->scratchpad);
}
* @param w: worker
* @param qinfo: query info. Pointer into packet buffer.
* @param edns: edns info from query.
+ * @param repinfo: reply information for a communication point.
* @param pkt: packet buffer.
* @return: true if a reply is to be sent.
*/
static int
-answer_chaos(struct worker* w, struct query_info* qinfo,
- struct edns_data* edns, sldns_buffer* pkt)
+answer_chaos(struct worker* w, struct query_info* qinfo,
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* pkt)
{
struct config_file* cfg = w->env.cfg;
if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT)
char buf[MAXHOSTNAMELEN+1];
if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
buf[MAXHOSTNAMELEN] = 0;
- chaos_replyonestr(pkt, buf, edns, w);
+ chaos_replyonestr(pkt, buf, edns, w, repinfo);
} else {
log_err("gethostname: %s", strerror(errno));
- chaos_replyonestr(pkt, "no hostname", edns, w);
+ chaos_replyonestr(pkt, "no hostname", edns, w, repinfo);
}
}
- else chaos_replyonestr(pkt, cfg->identity, edns, w);
+ else chaos_replyonestr(pkt, cfg->identity, edns, w, repinfo);
return 1;
}
if(query_dname_compare(qinfo->qname,
if(cfg->hide_version)
return 0;
if(cfg->version==NULL || cfg->version[0]==0)
- chaos_replyonestr(pkt, PACKAGE_STRING, edns, w);
- else chaos_replyonestr(pkt, cfg->version, edns, w);
+ chaos_replyonestr(pkt, PACKAGE_STRING, edns, w, repinfo);
+ else chaos_replyonestr(pkt, cfg->version, edns, w, repinfo);
return 1;
}
if(query_dname_compare(qinfo->qname,
{
if(cfg->hide_trustanchor)
return 0;
- chaos_trustanchor(pkt, edns, w);
+ chaos_trustanchor(pkt, edns, w, repinfo);
return 1;
}
if(c->type != comm_udp)
edns.udp_size = 65535; /* max size for TCP replies */
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
- &edns, c->buffer)) {
+ &edns, repinfo, c->buffer)) {
server_stats_insrcode(&worker->stats, c->buffer);
regional_free_all(worker->scratchpad);
goto send_reply;
}
if(worker->env.auth_zones &&
auth_zones_answer(worker->env.auth_zones, &worker->env,
- &qinfo, &edns, c->buffer, worker->scratchpad)) {
+ &qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) {
regional_free_all(worker->scratchpad);
if(sldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo);
+22 August 2018: George
+ - #4140: Expose repinfo (comm_reply) to the inplace_callbacks. This
+ gives access to reply information for the client's communication
+ point when the callback is called before the mesh state (modules).
+ Changes to C and Python's inplace_callback signatures were also
+ necessary.
+
21 August 2018: Wouter
- log-local-actions: yes option for unbound.conf that logs all the
local zone actions, a patch from Saksham Manchanda (Secure64).
return UB_NOERROR;
}
if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
- w->env, &qinfo, &edns, w->back->udp_buff, w->env->scratch)) {
+ w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
regional_free_all(w->env->scratch);
libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
w->back->udp_buff, sec_status_insecure, NULL, 0);
return UB_NOERROR;
}
if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
- w->env, &qinfo, &edns, w->back->udp_buff, w->env->scratch)) {
+ w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
regional_free_all(w->env->scratch);
free(qinfo.qname);
libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
return;
}
if(w->ctx->env->auth_zones && auth_zones_answer(w->ctx->env->auth_zones,
- w->env, &qinfo, &edns, w->back->udp_buff, w->env->scratch)) {
+ w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
regional_free_all(w->env->scratch);
q->msg_security = sec_status_insecure;
add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
.. code-block:: python
- def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
- """Function that will be registered as an inplace callback function.
+ def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
+ region, **kwargs):
+ """
+ Function that will be registered as an inplace callback function.
It will be called when answering with a resolved query.
+
:param qinfo: query_info struct;
:param qstate: module qstate. It contains the available opt_lists; It
SHOULD NOT be altered;
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
+ :param **kwargs: Dictionary that may contain parameters added in a future
+ release. Current parameters:
+ ``repinfo``: Reply information for a communication point (comm_reply).
+ It is None when the callback happens in the mesh states.
+
:return: True on success, False on failure.
+
"""
.. note:: The function's name is irrelevant.
.. code-block:: python
- def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
- """Function that will be registered as an inplace callback function.
+ def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
+ region, **kwargs):
+ """
+ Function that will be registered as an inplace callback function.
It will be called when answering from the cache.
+
:param qinfo: query_info struct;
:param qstate: module qstate. None;
:param rep: reply_info struct;
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
+ :param **kwargs: Dictionary that may contain parameters added in a future
+ release. Current parameters:
+ ``repinfo``: Reply information for a communication point (comm_reply).
+ It is None when the callback happens in the mesh
+ states(modules).
+
:return: True on success, False on failure.
+
+ For demonstration purposes we want to see if EDNS option 65002 is present
+ and reply with a new value.
+
"""
.. note:: The function's name is irrelevant.
.. code-block:: python
- def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
- """Function that will be registered as an inplace callback function.
+ def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
+ region, **kwargs):
+ """
+ Function that will be registered as an inplace callback function.
It will be called when answering from local data.
+
:param qinfo: query_info struct;
:param qstate: module qstate. None;
:param rep: reply_info struct;
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
+ :param **kwargs: Dictionary that may contain parameters added in a future
+ release. Current parameters:
+ ``repinfo``: Reply information for a communication point (comm_reply).
+ It is None when the callback happens in the mesh
+ states(modules).
+
:return: True on success, False on failure.
+
"""
.. note:: The function's name is irrelevant.
.. code-block:: python
- def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
- """Function that will be registered as an inplace callback function.
+ def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
+ region, **kwargs):
+ """
+ Function that will be registered as an inplace callback function.
It will be called when answering with SERVFAIL.
+
:param qinfo: query_info struct;
:param qstate: module qstate. If not None the relevant opt_lists are
available here;
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
+ :param **kwargs: Dictionary that may contain parameters added in a future
+ release. Current parameters:
+ ``repinfo``: Reply information for a communication point (comm_reply).
+ It is None when the callback happens in the mesh
+ states(modules).
+
:return: True on success, False on failure.
+
+ For demonstration purposes we want to reply with an empty EDNS code '65003'
+ and log the IP address(es) of the client(s).
+
"""
.. note:: The function's name is irrelevant.
Copyright (c) 2016, NLnet Labs.
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 organization nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
# This query returns SERVFAIL as the txt record of bogus.nlnetlabs.nl is
# intentionally bogus. The reply will contain an empty EDNS option
# with option code 65003.
+# Unbound will also log the source address(es) of the client(s) that made
+# the request.
# (unbound needs to be validating for this example to work)
# Useful functions:
def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
- region):
- """Function that will be registered as an inplace callback function.
+ region, **kwargs):
+ """
+ Function that will be registered as an inplace callback function.
It will be called when answering with a resolved query.
+
:param qinfo: query_info struct;
:param qstate: module qstate. It contains the available opt_lists; It
SHOULD NOT be altered;
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
+ :param **kwargs: Dictionary that may contain parameters added in a future
+ release. Current parameters:
+ ``repinfo``: Reply information for a communication point (comm_reply).
+ It is None when the callback happens in the mesh
+ states(modules).
+
:return: True on success, False on failure.
+
"""
log_info("python: called back while replying.")
return True
def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
- region):
- """Function that will be registered as an inplace callback function.
+ region, **kwargs):
+ """
+ Function that will be registered as an inplace callback function.
It will be called when answering from the cache.
+
:param qinfo: query_info struct;
:param qstate: module qstate. None;
:param rep: reply_info struct;
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
+ :param **kwargs: Dictionary that may contain parameters added in a future
+ release. Current parameters:
+ ``repinfo``: Reply information for a communication point (comm_reply).
+ It is None when the callback happens in the mesh
+ states(modules).
+
:return: True on success, False on failure.
For demonstration purposes we want to see if EDNS option 65002 is present
and reply with a new value.
+
"""
log_info("python: called back while answering from cache.")
# Inspect the incoming EDNS options.
def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
- region):
- """Function that will be registered as an inplace callback function.
+ region, **kwargs):
+ """
+ Function that will be registered as an inplace callback function.
It will be called when answering from local data.
+
:param qinfo: query_info struct;
:param qstate: module qstate. None;
:param rep: reply_info struct;
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
+ :param **kwargs: Dictionary that may contain parameters added in a future
+ release. Current parameters:
+ ``repinfo``: Reply information for a communication point (comm_reply).
+ It is None when the callback happens in the mesh
+ states(modules).
+
:return: True on success, False on failure.
+
"""
log_info("python: called back while replying with local data or chaos"
" reply.")
def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
- region):
- """Function that will be registered as an inplace callback function.
+ region, **kwargs):
+ """
+ Function that will be registered as an inplace callback function.
It will be called when answering with SERVFAIL.
+
:param qinfo: query_info struct;
:param qstate: module qstate. If not None the relevant opt_lists are
available here;
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
+ :param **kwargs: Dictionary that may contain parameters added in a future
+ release. Current parameters:
+ ``repinfo``: Reply information for a communication point (comm_reply).
+ It is None when the callback happens in the mesh
+ states(modules).
+
:return: True on success, False on failure.
- For demonstration purposes we want to reply with an empty EDNS code '65003'.
+ For demonstration purposes we want to reply with an empty EDNS code '65003'
+ and log the IP address(es) of the client(s).
+
"""
log_info("python: called back while servfail.")
+ # Append the example ENDS option
b = bytearray.fromhex("")
edns_opt_list_append(opt_list_out, 65003, b, region)
+
+ # Log the client(s) IP address(es)
+ comm_reply = kwargs['repinfo']
+ if comm_reply:
+ # If it is not None this callback was called before the query reached
+ # the mesh states(modules). There is only one client associated with
+ # this query.
+ addr = comm_reply.addr
+ port = comm_reply.port
+ addr_family = comm_reply.family
+ log_info("python: Client IP: {}({}), port: {}"
+ "".format(addr, addr_family, port))
+ else:
+ # If it is not None this callback was called while the query is in the
+ # mesh states(modules). In this case they may be multiple clients
+ # waiting for this query.
+ # The following code is the same as with the resip.py example.
+ rl = qstate.mesh_info.reply_list
+ while (rl):
+ if rl.query_reply:
+ q = rl.query_reply
+ log_info("python: Client IP: {}({}), port: {}"
+ "".format(q.addr, q.family, q.port))
+ rl = rl.next
+
+
return True
def init_standard(id, env):
- """New version of the init function.
+ """
+ New version of the init function.
+
The function's signature is the same as the C counterpart and allows for
extra functionality during init.
+
..note:: This function is preferred by unbound over the old init function.
..note:: The previously accessible configuration options can now be found in
env.cgf.
+
"""
log_info("python: inited script {}".format(env.cfg.python_script))
def init(id, cfg):
- """Previous version init function.
+ """
+ Previous version of the init function.
+
..note:: This function is still supported for backwards compatibility when
the init_standard function is missing. When init_standard is
present this function SHOULD be omitted to avoid confusion to the
reader.
+
"""
return True
def inform_super(id, qstate, superqstate, qdata): return True
def operate(id, event, qstate, qdata):
- print "Operate", event,"state:",qstate
+ print("Operate {} state: {}".format(event, qstate))
# Please note that if this module blocks, by moving to the validator
# to validate or iterator to lookup or spawn a subquery to look up,
msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_QR | PKT_RA | PKT_AA)
#append RR
if (qstate.qinfo.qtype == RR_TYPE_TXT) or (qstate.qinfo.qtype == RR_TYPE_ANY):
- rl = qstate.mesh_info.reply_list
- while (rl):
- if rl.query_reply:
- q = rl.query_reply
- # The TTL of 0 is mandatory, otherwise it ends up in
- # the cache, and is returned to other IP addresses.
- msg.answer.append("%s 0 IN TXT \"%s %d (%s)\"" % (qstate.qinfo.qname_str, q.addr,q.port,q.family))
- rl = rl.next
+ rl = qstate.mesh_info.reply_list
+ while (rl):
+ if rl.query_reply:
+ q = rl.query_reply
+ # The TTL of 0 is mandatory, otherwise it ends up in
+ # the cache, and is returned to other IP addresses.
+ msg.answer.append("%s 0 IN TXT \"%s %d (%s)\"" % (qstate.qinfo.qname_str, q.addr,q.port,q.family))
+ rl = rl.next
#set qstate.return_msg
if not msg.set_return_msg(qstate):
log_info("pythonmod: iterator module done")
qstate.ext_state[id] = MODULE_FINISHED
return True
-
+
log_err("pythonmod: bad event")
qstate.ext_state[id] = MODULE_ERROR
return True
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 regional* region, int id, void* python_callback)
+ struct comm_reply* repinfo, struct regional* region, int id,
+ void* python_callback)
{
PyObject *func, *py_edns, *py_qstate, *py_opt_list_out, *py_qinfo;
- PyObject *py_rep, *py_region;
- PyObject *result;
+ PyObject *py_rep, *py_repinfo, *py_region;
+ PyObject *py_args, *py_kwargs, *result;
int res = 0;
PyGILState_STATE gstate = PyGILState_Ensure();
SWIGTYPE_p_p_edns_option, 0);
py_qinfo = SWIG_NewPointerObj((void*) qinfo, SWIGTYPE_p_query_info, 0);
py_rep = SWIG_NewPointerObj((void*) rep, SWIGTYPE_p_reply_info, 0);
+ py_repinfo = SWIG_NewPointerObj((void*) repinfo, SWIGTYPE_p_comm_reply, 0);
py_region = SWIG_NewPointerObj((void*) region, SWIGTYPE_p_regional, 0);
- result = PyObject_CallFunction(func, "OOOiOOO", py_qinfo, py_qstate,
- py_rep, rcode, py_edns, py_opt_list_out, py_region);
+ 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);
+ result = PyObject_Call(func, py_args, py_kwargs);
Py_XDECREF(py_edns);
Py_XDECREF(py_qstate);
Py_XDECREF(py_opt_list_out);
Py_XDECREF(py_qinfo);
Py_XDECREF(py_rep);
+ Py_XDECREF(py_repinfo);
Py_XDECREF(py_region);
+ Py_XDECREF(py_args);
+ Py_XDECREF(py_kwargs);
if (result) {
res = PyInt_AsLong(result);
}
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 regional* region, int id, void* python_callback);
+ struct comm_reply* repinfo, struct regional* region, int id,
+ void* python_callback);
#endif /* PYTHONMOD_H */
/** encode auth answer */
static void
auth_answer_encode(struct query_info* qinfo, struct module_env* env,
- struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
- struct dns_msg* msg)
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, struct dns_msg* msg)
{
uint16_t udpsize;
udpsize = edns->udp_size;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, msg->rep,
- (int)FLAGS_GET_RCODE(msg->rep->flags), edns, temp)
+ (int)FLAGS_GET_RCODE(msg->rep->flags), edns, repinfo, temp)
|| !reply_info_answer_encode(qinfo, msg->rep,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2),
/** encode auth error answer */
static void
auth_error_encode(struct query_info* qinfo, struct module_env* env,
- struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
- int rcode)
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, int rcode)
{
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
- rcode, edns, temp))
+ rcode, edns, repinfo, temp))
edns->opt_list = NULL;
error_encode(buf, rcode|BIT_AA, qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
}
int auth_zones_answer(struct auth_zones* az, struct module_env* env,
- struct query_info* qinfo, struct edns_data* edns, struct sldns_buffer* buf,
- struct regional* temp)
+ struct query_info* qinfo, struct edns_data* edns,
+ struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp)
{
struct dns_msg* msg = NULL;
struct auth_zone* z;
/* encode answer */
if(!r)
- auth_error_encode(qinfo, env, edns, buf, temp,
+ auth_error_encode(qinfo, env, edns, repinfo, buf, temp,
LDNS_RCODE_SERVFAIL);
- else auth_answer_encode(qinfo, env, edns, buf, temp, msg);
+ else auth_answer_encode(qinfo, env, edns, repinfo, buf, temp, msg);
return 1;
}
* @param qinfo: query info (parsed).
* @param edns: edns info (parsed).
* @param buf: buffer with query ID and flags, also for reply.
+ * @param repinfo: reply information for a communication point.
* @param temp: temporary storage region.
* @return false if not answered
*/
int auth_zones_answer(struct auth_zones* az, struct module_env* env,
- struct query_info* qinfo, struct edns_data* edns, struct sldns_buffer* buf,
- struct regional* temp);
+ struct query_info* qinfo, struct edns_data* edns,
+ struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp);
/**
* Find the auth zone that is above the given qname.
/** encode answer consisting of 1 rrset */
static int
local_encode(struct query_info* qinfo, struct module_env* env,
- struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
- struct ub_packed_rrset_key* rrset, int ansec, int rcode)
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec,
+ int rcode)
{
struct reply_info rep;
uint16_t udpsize;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
- if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns, temp)
- || !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))
+ if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
+ repinfo, temp) || !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,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
+ }
return 1;
}
/** encode local error answer */
static void
local_error_encode(struct query_info* qinfo, struct module_env* env,
- struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
- int rcode, int r)
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, int rcode, int r)
{
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
- rcode, edns, temp))
+ rcode, edns, repinfo, temp))
edns->opt_list = NULL;
error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
/** answer local data match */
static int
local_data_answer(struct local_zone* z, struct module_env* env,
- struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
+ struct query_info* qinfo, struct edns_data* edns,
+ struct comm_reply* repinfo, sldns_buffer* buf,
struct regional* temp, int labs, struct local_data** ldp,
enum localzone_type lz_type, int tag, struct config_strlist** tag_datas,
size_t tag_datas_size, char** tagname, int num_tags)
* chain. */
if(qinfo->local_alias)
return 1;
- return local_encode(qinfo, env, edns, buf, temp,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp,
&r, 1, LDNS_RCODE_NOERROR);
}
}
struct ub_packed_rrset_key r = *lr->rrset;
r.rk.dname = qinfo->qname;
r.rk.dname_len = qinfo->qname_len;
- return local_encode(qinfo, env, edns, buf, temp, &r, 1,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1,
LDNS_RCODE_NOERROR);
}
- return local_encode(qinfo, env, edns, buf, temp, lr->rrset, 1,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1,
LDNS_RCODE_NOERROR);
}
/**
- * answer in case where no exact match is found
- * @param z: zone for query
- * @param env: module environment
- * @param qinfo: query
- * @param edns: edns from query
+ * Answer in case where no exact match is found.
+ * @param z: zone for query.
+ * @param env: module environment.
+ * @param qinfo: query.
+ * @param edns: edns from query.
+ * @param repinfo: source address for checks. may be NULL.
* @param buf: buffer for answer.
- * @param temp: temp region for encoding
+ * @param temp: temp region for encoding.
* @param ld: local data, if NULL, no such name exists in localdata.
- * @param lz_type: type of the local zone
+ * @param lz_type: type of the local zone.
* @return 1 if a reply is to be sent, 0 if not.
*/
static int
lz_zone_answer(struct local_zone* z, struct module_env* env,
- struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
- struct regional* temp, struct local_data* ld, enum localzone_type lz_type)
+ struct query_info* qinfo, struct edns_data* edns,
+ struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
+ struct local_data* ld, enum localzone_type lz_type)
{
if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) {
/** no reply at all, signal caller by clearing buffer. */
return 1;
} else if(lz_type == local_zone_refuse
|| lz_type == local_zone_always_refuse) {
- local_error_encode(qinfo, env, edns, buf, temp,
+ local_error_encode(qinfo, env, edns, repinfo, buf, temp,
LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA));
return 1;
} else if(lz_type == local_zone_static ||
int rcode = (ld || lz_type == local_zone_redirect)?
LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
if(z->soa)
- return local_encode(qinfo, env, edns, buf, temp,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa, 0, rcode);
- local_error_encode(qinfo, env, edns, buf, temp, rcode,
+ local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
(rcode|BIT_AA));
return 1;
} else if(lz_type == local_zone_typetransparent
if(ld && ld->rrsets) {
int rcode = LDNS_RCODE_NOERROR;
if(z->soa)
- return local_encode(qinfo, env, edns, buf, temp,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa, 0, rcode);
- local_error_encode(qinfo, env, edns, buf, temp, rcode,
+ local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
(rcode|BIT_AA));
return 1;
}
if(lzt != local_zone_always_refuse
&& lzt != local_zone_always_transparent
&& lzt != local_zone_always_nxdomain
- && local_data_answer(z, env, qinfo, edns, buf, temp, labs, &ld, lzt,
- tag, tag_datas, tag_datas_size, tagname, num_tags)) {
+ && local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs,
+ &ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) {
lock_rw_unlock(&z->lock);
/* We should tell the caller that encode is deferred if we found
* a local alias. */
return !qinfo->local_alias;
}
- r = lz_zone_answer(z, env, qinfo, edns, buf, temp, ld, lzt);
+ r = lz_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt);
lock_rw_unlock(&z->lock);
return r && !qinfo->local_alias; /* see above */
}
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, mesh->env->scratch))
+ LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
edns->opt_list = NULL;
error_encode(rep->c->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, mesh->env->scratch))
+ NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
edns->opt_list = NULL;
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) {
log_err("mesh_new_client: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
- NULL, LDNS_RCODE_SERVFAIL, edns, mesh->env->scratch))
+ NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
edns->opt_list = NULL;
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
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, m->s.region))
+ rep, rcode, &r->edns, NULL, m->s.region))
r->edns.opt_list = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
- &r->edns, m->s.region))
+ &r->edns, NULL, m->s.region))
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, m->s.region) ||
+ LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region) ||
!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, m->s.region))
+ rep, rcode, &r->edns, NULL, m->s.region))
r->edns.opt_list = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
- &r->edns, m->s.region))
+ &r->edns, NULL, m->s.region))
r->edns.opt_list = NULL;
}
error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo,
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, m->s.region) ||
+ LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region) ||
!apply_edns_options(&r->edns, &edns_bak,
m->s.env->cfg, r->query_reply.c,
m->s.region) ||
(int)(r->edns.bits & EDNS_DO), secure))
{
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, LDNS_RCODE_SERVFAIL, &r->edns, m->s.region))
+ rep, LDNS_RCODE_SERVFAIL, &r->edns, NULL, m->s.region))
r->edns.opt_list = NULL;
error_encode(r->query_reply.c->buffer,
LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid,
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 regional* region)
+ struct comm_reply* repinfo, struct regional* region)
{
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, region, cb->id, cb->cb_arg);
+ rcode, edns, &opt_list_out, repinfo, region, 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 regional* region)
+ struct edns_data* edns, struct comm_reply* repinfo, struct regional* region)
{
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo,
- qstate, rep, rcode, edns, region);
+ qstate, rep, rcode, edns, repinfo, region);
}
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 regional* region)
+ struct comm_reply* repinfo, struct regional* region)
{
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache,
- qinfo, qstate, rep, rcode, edns, region);
+ qinfo, qstate, rep, rcode, edns, repinfo, region);
}
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 regional* region)
+ struct comm_reply* repinfo, struct regional* region)
{
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local,
- qinfo, qstate, rep, rcode, edns, region);
+ qinfo, qstate, rep, rcode, edns, repinfo, region);
}
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 regional* region)
+ struct comm_reply* repinfo, struct regional* region)
{
/* We are going to servfail. Remove any potential edns options. */
if(qstate)
qstate->edns_opts_front_out = NULL;
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply_servfail],
- inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, region);
+ inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, repinfo,
+ region);
}
int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
* @param rep: Reply info. Could be NULL.
* @param rcode: return code.
* @param edns: edns data of the reply.
+ * @param repinfo: comm_reply. NULL.
* @param region: region to store data.
* @return false on failure (a callback function returned an error).
*/
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 regional* region);
+ struct edns_data* edns, struct comm_reply* repinfo, struct regional* region);
/**
* Call the registered functions in the inplace_cb_reply_cache linked list.
* @param rep: Reply info.
* @param rcode: return code.
* @param edns: edns data of the reply. Edns input can be found here.
+ * @param repinfo: comm_reply. Reply information for a communication point.
* @param region: region to store data.
* @return false on failure (a callback function returned an error).
*/
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 regional* region);
+ struct comm_reply* repinfo, struct regional* region);
/**
* Call the registered functions in the inplace_cb_reply_local linked list.
* @param rep: Reply info.
* @param rcode: return code.
* @param edns: edns data of the reply. Edns input can be found here.
+ * @param repinfo: comm_reply. Reply information for a communication point.
* @param region: region to store data.
* @return false on failure (a callback function returned an error).
*/
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 regional* region);
+ struct comm_reply* repinfo, struct regional* region);
/**
* Call the registered functions in the inplace_cb_reply linked list.
* @param rcode: return code. LDNS_RCODE_SERVFAIL.
* @param edns: edns data of the reply. Edns input can be found here if qstate
* is NULL.
+ * @param repinfo: comm_reply. Reply information for a communication point.
* @param region: region to store data.
* @return false on failure (a callback function returned an error).
*/
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 regional* region);
+ struct comm_reply* repinfo, struct regional* region);
/**
* Call the registered functions in the inplace_cb_query linked list.
/**
* Inplace callback function called before replying.
- * Called as func(edns, qstate, opt_list_out, qinfo, reply_info, rcode,
- * region, python_callback)
+ * Called as func(qinfo, qstate, rep, rcode, edns, opt_list_out, repinfo,
+ * region, id, python_callback)
* Where:
* qinfo: the query info.
* qstate: the module state. NULL when calling before the query reaches the
* edns: the edns_data of the reply. When qstate is NULL, it is also used as
* the edns input.
* opt_list_out: the edns options list for the reply.
+ * repinfo: reply information for a communication point. NULL when calling
+ * during the mesh states; the same could be found from
+ * qstate->mesh_info->reply_list.
* region: region to store data.
+ * id: module id.
* python_callback: only used for registering a python callback function.
*/
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 regional* region, int id, void* callback);
+ struct edns_data* edns, struct edns_option** opt_list_out,
+ struct comm_reply* repinfo, struct regional* region, int id,
+ void* callback);
/**
* Inplace callback function called before sending the query to a nameserver.
* Called as func(qinfo, flags, qstate, addr, addrlen, zone, zonelen, region,
- * python_callback)
+ * id, python_callback)
* Where:
* qinfo: query info.
* flags: flags of the query.
* authoritative.
* zonelen: length of zone.
* region: region to store data.
+ * id: module id.
* python_callback: only used for registering a python callback function.
*/
typedef int inplace_cb_query_func_type(struct query_info* qinfo, uint16_t flags,
/**
* Inplace callback function called after parsing edns on query reply.
- * Called as func(qstate, cb_args)
+ * Called as func(qstate, id, cb_args)
* Where:
- * qstate: the query state
- * id: module id
+ * qstate: the query state.
+ * id: module id.
* cb_args: argument passed when registering callback.
*/
typedef int inplace_cb_edns_back_parsed_func_type(struct module_qstate* qstate,
/**
* Inplace callback function called after parsing query response.
- * Called as func(qstate, id, cb_args)
+ * Called as func(qstate, response, id, cb_args)
* Where:
- * qstate: the query state
- * response: query response
- * id: module id
+ * qstate: the query state.
+ * response: query response.
+ * id: module id.
* cb_args: argument passed when registering callback.
*/
typedef int inplace_cb_query_response_func_type(struct module_qstate* qstate,