Commit bcf3f4b5 authored by Karel Slaný's avatar Karel Slaný Committed by Ondřej Surý

Added library callback for finalising outbound queries.

parent 1bd65aec
......@@ -25,11 +25,6 @@
#include <malloc.h>
#endif
#include <assert.h>
#if defined(ENABLE_COOKIES)
#include <arpa/inet.h> /* inet_ntop() */
#include "lib/cookies/control.h"
#include "lib/cookies/helper.h"
#endif /* defined(ENABLE_COOKIES) */
#include "lib/utils.h"
#include "lib/layer.h"
#include "daemon/worker.h"
......@@ -449,59 +444,6 @@ static void on_write(uv_write_t *req, int status)
req_release(worker, (struct req *)req);
}
#if defined(ENABLE_COOKIES)
/** Update DNS cookie data in packet. */
static bool subreq_update_cookies(struct qr_task *task, uv_udp_t *handle,
struct sockaddr *srvr_addr, knot_pkt_t *pkt)
{
assert(task);
assert(handle);
assert(pkt);
/* RFC7873 4.1 strongly requires server address. */
if (!srvr_addr) {
return false;
}
struct kr_cookie_settings *clnt_sett = &task->req.ctx->cookie_ctx.clnt;
/* Cookies disabled or packet has no ENDS section. */
if (!clnt_sett->enabled || !pkt->opt_rr) {
return true;
}
struct sockaddr_storage *sockaddr_ptr = NULL; /* Not supported yet. */
#if 0
/*
* RFC7873 4.1 recommends using also the client address. The matter is
* also discussed in section 6.
*
* Libuv does not offer a convenient way how to obtain a source IP
* address from a UDP handle that has been initialised using
* uv_udp_init(). The uv_udp_getsockname() fails because of the lazy
* socket initialisation.
*
* @note -- A solution might be opening a separate socket and trying
* to obtain the IP address from it.
*/
struct sockaddr_storage sockaddr = {0, };
struct sockaddr_storage *sockaddr_ptr = &sockaddr;
int sockaddr_len = sizeof(sockaddr);
int ret = uv_udp_getsockname(handle, (struct sockaddr*) &sockaddr,
&sockaddr_len);
if (ret != 0) {
sockaddr_ptr = NULL;
}
#endif /* 0 */
kr_request_put_cookie(&clnt_sett->current,
task->worker->engine->resolver.cache_cookie,
(struct sockaddr*) sockaddr_ptr, srvr_addr, pkt);
return true;
}
#endif /* defined(ENABLE_COOKIES) */
static int qr_task_send(struct qr_task *task, uv_handle_t *handle, struct sockaddr *addr, knot_pkt_t *pkt)
{
if (!handle) {
......@@ -515,27 +457,23 @@ static int qr_task_send(struct qr_task *task, uv_handle_t *handle, struct sockad
return qr_task_on_send(task, handle, ret);
}
/* Send using given protocol */
int ret = 0;
struct req *send_req = req_borrow(task->worker);
if (!send_req) {
return qr_task_on_send(task, handle, kr_error(ENOMEM));
}
if (handle->type == UV_UDP) {
#if defined(ENABLE_COOKIES)
/* The actual server IP address is needed before generating the
* actual cookie. If we don't know the server address then we
* also don't know the actual cookie size.
* Also the resolver somehow mangles the query packets before
* building the query i.e. the space needed for the cookie
* cannot be allocated in the cookie layer. */
if (knot_wire_get_qr(pkt->wire) == 0) {
/* Update DNS cookies data in query. */
subreq_update_cookies(task, (uv_udp_t *) handle, addr,
pkt);
if (knot_wire_get_qr(pkt->wire) == 0) {
/* Query must be finalised using destination address before sending. */
ret = kr_resolve_query_finalize(&task->req, addr,
handle->type == UV_UDP ? SOCK_DGRAM : SOCK_STREAM,
pkt);
if (ret == KNOT_STATE_FAIL) {
return kr_error(EINVAL); /* @todo: What error code should it return. */
}
#endif /* defined(ENABLE_COOKIES) */
}
/* Send using given protocol */
ret = 0;
if (handle->type == UV_UDP) {
uv_buf_t buf = { (char *)pkt->wire, pkt->size };
send_req->as.send.data = task;
ret = uv_udp_send(&send_req->as.send, (uv_udp_t *)handle, &buf, 1, addr, &on_send);
......
......@@ -844,12 +844,101 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
return KNOT_STATE_PRODUCE;
}
/* Prepare additional query */
/*
* Additional query is going to be finalised when calling
* kr_resolve_query_finalize().
*/
gettimeofday(&qry->timestamp, NULL);
*dst = &qry->ns.addr[0].ip;
*type = (qry->flags & QUERY_TCP) ? SOCK_STREAM : SOCK_DGRAM;
return request->state;
}
#if defined(ENABLE_COOKIES)
/** Update DNS cookie data in packet. */
static bool outbound_query_add_cookies(struct kr_request *req,
const struct sockaddr *dst,
knot_pkt_t *pkt)
{
assert(req);
assert(pkt);
/* RFC7873 4.1 strongly requires server address. */
if (!dst) {
return false;
}
struct kr_cookie_settings *clnt_sett = &req->ctx->cookie_ctx.clnt;
/* Cookies disabled or packet has no ENDS section. */
if (!clnt_sett->enabled || !pkt->opt_rr) {
return true;
}
/*
* RFC7873 4.1 recommends using also the client address. The matter is
* also discussed in section 6.
*
* Libuv does not offer a convenient way how to obtain a source IP
* address from a UDP handle that has been initialised using
* uv_udp_init(). The uv_udp_getsockname() fails because of the lazy
* socket initialisation.
*
* @note -- A solution might be opening a separate socket and trying
* to obtain the IP address from it.
*/
kr_request_put_cookie(&clnt_sett->current, req->ctx->cache_cookie,
NULL, dst, pkt);
return true;
}
#endif /* defined(ENABLE_COOKIES) */
int kr_resolve_query_finalize(struct kr_request *request, struct sockaddr *dst, int type, knot_pkt_t *packet)
{
/* @todo: Update documentation if this function becomes approved. */
struct kr_rplan *rplan = &request->rplan;
if (knot_wire_get_qr(packet->wire) != 0) {
return request->state;
}
/* No query left for resolution */
if (kr_rplan_empty(rplan)) {
return KNOT_STATE_FAIL;
}
/* If we have deferred answers, resume them. */
struct kr_query *qry = array_tail(rplan->pending);
/*
* @todo: Expose this point into the layers/modules?
* pros: Cookie control structure and LRU cache can be stored in module.
* cons: Additional stress on API before sending every packet.
*/
int ret = query_finalize(request, qry, packet);
if (ret != 0) {
return KNOT_STATE_FAIL;
}
#if defined(ENABLE_COOKIES)
/* Update DNS cookies data in query. */
if (type == SOCK_DGRAM) { /* @todo: Add cookies also over TCP? */
/* The actual server IP address is needed before generating the
* actual cookie. If we don't know the server address then we
* also don't know the actual cookie size.
* Also the resolver somehow mangles the query packets before
* building the query i.e. the space needed for the cookie
* cannot be allocated in the cookie layer. */
if (!outbound_query_add_cookies(request, dst, packet)) {
return KNOT_STATE_FAIL;
}
}
#endif /* defined(ENABLE_COOKIES) */
WITH_DEBUG {
char qname_str[KNOT_DNAME_MAXLEN], zonecut_str[KNOT_DNAME_MAXLEN], ns_str[INET6_ADDRSTRLEN], type_str[16];
knot_dname_to_str(qname_str, knot_pkt_qname(packet), sizeof(qname_str));
......@@ -867,9 +956,6 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
}
}
gettimeofday(&qry->timestamp, NULL);
*dst = &qry->ns.addr[0].ip;
*type = (qry->flags & QUERY_TCP) ? SOCK_STREAM : SOCK_DGRAM;
return request->state;
}
......
......@@ -177,6 +177,20 @@ int kr_resolve_consume(struct kr_request *request, const struct sockaddr *src, k
KR_EXPORT
int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *type, knot_pkt_t *packet);
/**
* Finalises the query with the knowledge of the target (remote server) IP address.
*
* @note The function must be called before actual sending of the request packet.
*
* @param request request state (in PRODUCE state)
* @param dst address of the name server
* @param type used socket type (SOCK_STREAM, SOCK_DGRAM)
* @param packet [in,out] query packet to be finalised
* @return any state
*/
KR_EXPORT
int kr_resolve_query_finalize(struct kr_request *request, struct sockaddr *dst, int type, knot_pkt_t *packet);
/**
* Finish resolution and commit results if the state is DONE.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment