diff --git a/daemon/worker.c b/daemon/worker.c index a4d1b9de01b09796a60edc44408aa703ab62e6c6..d5aa0e0d36b2caad41009216249b7cc5dc9c9209 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -61,7 +61,7 @@ static int parse_query(knot_pkt_t *query) return kr_ok(); } -static struct qr_task *qr_task_create(struct worker_ctx *worker, uv_handle_t *handle, const struct sockaddr *addr) +static struct qr_task *qr_task_create(struct worker_ctx *worker, uv_handle_t *handle, knot_pkt_t *query, const struct sockaddr *addr) { mm_ctx_t pool; mm_ctx_mempool(&pool, MM_DEFAULT_BLKSIZE); @@ -80,15 +80,28 @@ static struct qr_task *qr_task_create(struct worker_ctx *worker, uv_handle_t *ha memcpy(&task->source.addr, addr, sockaddr_len(addr)); } + /* How much can client handle? */ + size_t answer_max = KNOT_WIRE_MIN_PKTSIZE; + if (!addr) { /* TCP */ + answer_max = KNOT_WIRE_MAX_PKTSIZE; + } else if (knot_pkt_has_edns(query)) { /* EDNS */ + answer_max = knot_edns_get_payload(query->opt_rr); + } + /* How much space do we need for intermediate packets? */ + size_t pktbuf_max = KNOT_EDNS_MAX_UDP_PAYLOAD; + if (pktbuf_max < answer_max) { + pktbuf_max = answer_max; + } + /* Create buffers */ - knot_pkt_t *next_query = knot_pkt_new(NULL, KNOT_EDNS_MAX_UDP_PAYLOAD, &task->req.pool); - knot_pkt_t *answer = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, &task->req.pool); - if (!next_query || !answer) { + knot_pkt_t *pktbuf = knot_pkt_new(NULL, pktbuf_max, &task->req.pool); + knot_pkt_t *answer = knot_pkt_new(NULL, answer_max, &task->req.pool); + if (!pktbuf || !answer) { mp_delete(pool.ctx); return NULL; } task->req.answer = answer; - task->next_query = next_query; + task->next_query = pktbuf; /* Start resolution */ uv_timer_init(handle->loop, &task->timeout); @@ -240,7 +253,7 @@ int worker_exec(struct worker_ctx *worker, uv_handle_t *handle, knot_pkt_t *quer if (ret != 0 || knot_wire_get_qr(query->wire)) { return kr_error(EINVAL); /* Ignore. */ } - task = qr_task_create(worker, handle, addr); + task = qr_task_create(worker, handle, query, addr); if (!task) { return kr_error(ENOMEM); }