]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
Added library callback for finalising outbound queries.
authorKarel Slany <karel.slany@nic.cz>
Mon, 18 Jul 2016 15:38:36 +0000 (17:38 +0200)
committerOndřej Surý <ondrej@sury.org>
Thu, 11 Aug 2016 12:06:45 +0000 (14:06 +0200)
daemon/worker.c
lib/resolve.c
lib/resolve.h

index f1bc2f9ffd6a65aaa7d4d3b4ed20a20515f79d9d..b4ce214c8480a007aeebff8f1d7df10c425e6fb2 100644 (file)
 #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);
index 0c0ac3485532eec239ff2a0f2e133c8a92191401..2e910f943fc4ad33cf25f85d2d564c5081a7cdfc 100644 (file)
@@ -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;
 }
 
index 46e8e0cd36b4ccea18d30b6d8586aa24687c9131..d39da76f118c654a555435a1de32c716bc4c7411 100644 (file)
@@ -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.
  *