From: Karel Slany Date: Mon, 18 Jul 2016 15:38:36 +0000 (+0200) Subject: Added library callback for finalising outbound queries. X-Git-Tag: v1.1.0~2^2~46 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bcf3f4b54d2266cdd268541b6963a3408d260dbd;p=thirdparty%2Fknot-resolver.git Added library callback for finalising outbound queries. --- diff --git a/daemon/worker.c b/daemon/worker.c index f1bc2f9ff..b4ce214c8 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -25,11 +25,6 @@ #include #endif #include -#if defined(ENABLE_COOKIES) -#include /* 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); diff --git a/lib/resolve.c b/lib/resolve.c index 0c0ac3485..2e910f943 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -844,12 +844,101 @@ ns_election: 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 @@ ns_election: } } - gettimeofday(&qry->timestamp, NULL); - *dst = &qry->ns.addr[0].ip; - *type = (qry->flags & QUERY_TCP) ? SOCK_STREAM : SOCK_DGRAM; return request->state; } diff --git a/lib/resolve.h b/lib/resolve.h index 46e8e0cd3..d39da76f1 100644 --- a/lib/resolve.h +++ b/lib/resolve.h @@ -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. *