#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"
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) {
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);
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));
}
}
- gettimeofday(&qry->timestamp, NULL);
- *dst = &qry->ns.addr[0].ip;
- *type = (qry->flags & QUERY_TCP) ? SOCK_STREAM : SOCK_DGRAM;
return request->state;
}
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.
*