diff --git a/daemon/worker.c b/daemon/worker.c index a35bc171456f17b0ac9936543a50f15a3517e0c1..a518e2066dc345f277c1420a8f4c95847857a615 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -30,11 +30,7 @@ struct qr_task knot_pkt_t *next_query; uv_handle_t *next_handle; uv_timer_t timeout; - union { - uv_write_t tcp_send; - uv_udp_send_t udp_send; - uv_connect_t connect; - } ioreq; + uv_connect_t connect; struct { union { struct sockaddr_in ip4; @@ -117,8 +113,6 @@ static void qr_task_timeout(uv_timer_t *req) { struct qr_task *task = req->data; if (task->next_handle) { - uv_cancel((uv_req_t *)&task->ioreq); - io_stop_read(task->next_handle); qr_task_step(task, NULL); } } @@ -160,7 +154,8 @@ static void qr_task_on_connect(uv_connect_t *connect, int status) { uv_stream_t *handle = connect->handle; struct qr_task *task = connect->data; - if (status == 0) { /* Failed to connect */ + /* Use only if succeeded, and the connection didn't change. */ + if (status == 0 && ((uv_handle_t *)handle == task->next_handle)) { qr_task_send(task, (uv_handle_t *)handle, NULL, task->next_query); } } @@ -177,10 +172,12 @@ static int qr_task_step(struct qr_task *task, knot_pkt_t *packet) /* Cancel timeout if active, close handle. */ if (task->next_handle) { if (!uv_is_closing(task->next_handle)) { + io_stop_read(task->next_handle); uv_close(task->next_handle, (uv_close_cb) free); } uv_timer_stop(&task->timeout); task->next_handle = NULL; + task->connect.handle = NULL; } /* Consume input and produce next query */ @@ -209,7 +206,7 @@ static int qr_task_step(struct qr_task *task, knot_pkt_t *packet) /* Connect or issue query datagram */ task->next_handle->data = task; if (sock_type == SOCK_STREAM) { - uv_connect_t *connect = &task->ioreq.connect; + uv_connect_t *connect = &task->connect; connect->data = task; if (uv_tcp_connect(connect, (uv_tcp_t *)task->next_handle, addr, qr_task_on_connect) != 0) { return qr_task_step(task, NULL); diff --git a/lib/layer/pktcache.c b/lib/layer/pktcache.c index 050aec156255e35320b7e1c11b12af6f0289cdd5..15891294a1c874a3e10611f8787bbb53cc8acfa1 100644 --- a/lib/layer/pktcache.c +++ b/lib/layer/pktcache.c @@ -54,10 +54,9 @@ static void adjust_ttl(knot_rrset_t *rr, uint32_t drift) } } -static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, uint8_t tag, uint32_t timestamp) +static int loot_cache_pkt(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *qname, + uint16_t rrtype, uint8_t tag, uint32_t timestamp) { - const knot_dname_t *qname = knot_pkt_qname(pkt); - uint16_t rrtype = knot_pkt_qtype(pkt); struct kr_cache_entry *entry; entry = kr_cache_peek(txn, tag, qname, rrtype, ×tamp); if (!entry) { /* Not in the cache */ @@ -91,6 +90,25 @@ static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, uint8_t tag, uint32_t return ret; } +/** @internal Try to find a shortcut directly to searched packet, otherwise try to find minimised QNAME. */ +static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, uint8_t tag, struct kr_query *qry) +{ + uint32_t timestamp = qry->timestamp.tv_sec; + const knot_dname_t *qname = qry->sname; + uint16_t rrtype = qry->stype; + int ret = loot_cache_pkt(txn, pkt, qname, rrtype, tag, timestamp); + if (ret == 0) { /* Signalize minimisation disabled */ + qry->flags |= QUERY_NO_MINIMIZE; + } else { /* Retry with minimised name */ + qname = knot_pkt_qname(pkt); + rrtype = knot_pkt_qtype(pkt); + if (!knot_dname_is_equal(qname, qry->sname)) { + ret = loot_cache_pkt(txn, pkt, qname, rrtype, tag, timestamp); + } + } + return ret; +} + static int peek(knot_layer_t *ctx, knot_pkt_t *pkt) { struct kr_request *req = ctx->data; @@ -103,24 +121,25 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt) return ctx->state; /* Only IN class */ } - /* Fetch packet from cache */ + /* Prepare read transaction */ namedb_txn_t txn; struct kr_cache *cache = req->ctx->cache; if (kr_cache_txn_begin(cache, &txn, NAMEDB_RDONLY) != 0) { return ctx->state; } - uint32_t timestamp = qry->timestamp.tv_sec; - if (loot_cache(&txn, pkt, get_tag(req->answer), timestamp) != 0) { - kr_cache_txn_abort(&txn); - return ctx->state; - } - /* Mark as solved from cache */ - DEBUG_MSG("=> satisfied from cache\n"); - qry->flags |= QUERY_CACHED; - knot_wire_set_qr(pkt->wire); + /* Fetch either answer to original or minimized query */ + uint8_t tag = get_tag(req->answer); + int ret = loot_cache(&txn, pkt, tag, qry); kr_cache_txn_abort(&txn); - return KNOT_STATE_DONE; + if (ret == 0) { + DEBUG_MSG("=> satisfied from cache\n"); + qry->flags |= QUERY_CACHED; + pkt->parsed = pkt->size; + knot_wire_set_qr(pkt->wire); + return KNOT_STATE_DONE; + } + return ctx->state; } static uint32_t packet_ttl(knot_pkt_t *pkt) diff --git a/lib/layer/rrcache.c b/lib/layer/rrcache.c index 2b23742ae290efffd81af18a5dbf05e3b5fb40ee..ea885b6135df86d1dab8a726647766d35fa374b0 100644 --- a/lib/layer/rrcache.c +++ b/lib/layer/rrcache.c @@ -33,18 +33,28 @@ static int begin(knot_layer_t *ctx, void *module_param) } static int loot_rr(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *name, - uint16_t rrtype, uint16_t rrclass, uint32_t timestamp) + uint16_t rrclass, uint16_t rrtype, struct kr_query *qry) { + /* Check if record exists in cache */ + uint32_t timestamp = qry->timestamp.tv_sec; knot_rrset_t cache_rr; knot_rrset_init(&cache_rr, (knot_dname_t *)name, rrtype, rrclass); int ret = kr_cache_peek_rr(txn, &cache_rr, ×tamp); if (ret != 0) { return ret; } - knot_rrset_t rr_copy = kr_cache_materialize(&cache_rr, timestamp, &pkt->mm); - if (rr_copy.rrs.rr_count == 0) { - return kr_error(ENOENT); + + /* Update packet question */ + if (!knot_dname_is_equal(knot_pkt_qname(pkt), name)) { + uint8_t header[KNOT_WIRE_HEADER_SIZE]; + memcpy(header, pkt->wire, sizeof(header)); + knot_pkt_clear(pkt); + memcpy(pkt->wire, header, sizeof(header)); + knot_pkt_put_question(pkt, qry->sname, qry->sclass, qry->stype); } + + /* Update packet answer */ + knot_rrset_t rr_copy = kr_cache_materialize(&cache_rr, timestamp, &pkt->mm); ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, &rr_copy, KNOT_PF_FREE); if (ret != 0) { knot_rrset_clear(&rr_copy, &pkt->mm); @@ -53,14 +63,31 @@ static int loot_rr(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *name, return kr_ok(); } -static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, uint32_t timestamp) +static int loot_cache_set(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *qname, + uint16_t rrclass, uint16_t rrtype, struct kr_query *qry) { - const knot_dname_t *qname = knot_pkt_qname(pkt); - uint16_t rrclass = knot_pkt_qclass(pkt); - uint16_t rrtype = knot_pkt_qtype(pkt); - int ret = loot_rr(txn, pkt, qname, rrtype, rrclass, timestamp); + int ret = loot_rr(txn, pkt, qname, rrclass, rrtype, qry); if (ret == kr_error(ENOENT) && rrtype != KNOT_RRTYPE_CNAME) { /* Chase CNAME if no direct hit */ - ret = loot_rr(txn, pkt, qname, KNOT_RRTYPE_CNAME, rrclass, timestamp); + ret = loot_rr(txn, pkt, qname, rrclass, KNOT_RRTYPE_CNAME, qry); + } + return ret; +} + +/** @internal Try to find a shortcut directly to searched record, otherwise try to find minimised QNAME. */ +static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, struct kr_query *qry) +{ + const knot_dname_t *qname = qry->sname; + uint16_t rrclass = qry->sclass; + uint16_t rrtype = qry->stype; + int ret = loot_cache_set(txn, pkt, qname, rrclass, rrtype, qry); + if (ret == 0) { /* Signalize minimisation disabled */ + qry->flags |= QUERY_NO_MINIMIZE; + } else { /* Retry with minimised name */ + qname = knot_pkt_qname(pkt); + rrtype = knot_pkt_qtype(pkt); + if (!knot_dname_is_equal(qname, qry->sname)) { + ret = loot_cache_set(txn, pkt, qname, rrclass, rrtype, qry); + } } return ret; } @@ -77,21 +104,21 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt) namedb_txn_t txn; struct kr_cache *cache = req->ctx->cache; if (kr_cache_txn_begin(cache, &txn, NAMEDB_RDONLY) != 0) { - return KNOT_STATE_CONSUME; + return ctx->state; } /* Reconstruct the answer from the cache, * it may either be a CNAME chain or direct answer. * Only one step of the chain is resolved at a time. */ - uint32_t timestamp = qry->timestamp.tv_sec; - int ret = loot_cache(&txn, pkt, timestamp); + int ret = loot_cache(&txn, pkt, qry); kr_cache_txn_abort(&txn); if (ret == 0) { DEBUG_MSG("=> satisfied from cache\n"); qry->flags |= QUERY_CACHED; pkt->parsed = pkt->size; knot_wire_set_qr(pkt->wire); + knot_wire_set_aa(pkt->wire); return KNOT_STATE_DONE; } return ctx->state; diff --git a/scripts/Dockerfile b/scripts/Dockerfile index ce174414ea7ae7396cbb3393b7b9270fd6c6e618..6d5084bd3812cb037a9c92ab706ca350fe8e934e 100644 --- a/scripts/Dockerfile +++ b/scripts/Dockerfile @@ -9,6 +9,7 @@ ENV PREFIX /usr/local ENV BUILD_DIR /tmp/build ENV BUILD_IGNORE gmp nettle jansson gnutls lua ENV CFLAGS -DNDEBUG -O2 -g -fstack-protector +ENV LDFLAGS -Wl,--as-needed # Expose port EXPOSE 53