From 7291e8038cc802c52acee78647a58cdc897442b2 Mon Sep 17 00:00:00 2001 From: Grigorii Demidov Date: Wed, 14 Mar 2018 14:21:01 +0100 Subject: [PATCH] daemon: check source in udp answer --- daemon/io.c | 6 ++++++ daemon/worker.c | 11 +++++++++-- lib/utils.c | 27 +++++++++++++++++++++++++++ lib/utils.h | 5 +++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/daemon/io.c b/daemon/io.c index 63bca9f71..494a5eb37 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -160,6 +160,12 @@ void udp_recv(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, if (addr->sa_family == AF_UNSPEC) { return; } + if (s->outgoing) { + assert(s->peer.ip.sa_family != AF_UNSPEC); + if (kr_sockaddr_cmp(&s->peer.ip, addr) != 0) { + return; + } + } knot_pkt_t *query = knot_pkt_new(buf->base, nread, &worker->pkt_pool); if (query) { query->max_size = KNOT_WIRE_MAX_PKTSIZE; diff --git a/daemon/worker.c b/daemon/worker.c index adf4c4f64..6e17eee39 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1384,8 +1384,15 @@ static uv_handle_t *retransmit(struct qr_task *task) return ret; } ret = ioreq_spawn(task, SOCK_DGRAM, choice->sin6_family); - if (ret && - qr_task_send(task, ret, (struct sockaddr *)choice, + if (!ret) { + return ret; + } + struct sockaddr *addr = (struct sockaddr *)choice; + struct session *session = ret->data; + assert (session->peer.ip.sa_family == AF_UNSPEC); + session->outgoing = true; + memcpy(&session->peer, addr, sizeof(session->peer)); + if (qr_task_send(task, ret, (struct sockaddr *)choice, task->pktbuf) == 0) { task->addrlist_turn = (task->addrlist_turn + 1) % task->addrlist_count; /* Round robin */ diff --git a/lib/utils.c b/lib/utils.c index 91bad8fdc..62c61e3b8 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -365,6 +365,33 @@ int kr_sockaddr_len(const struct sockaddr *addr) } } +int kr_sockaddr_cmp(const struct sockaddr *left, const struct sockaddr *right) +{ + if (!left || !right) { + return kr_error(EINVAL); + } + if (left->sa_family != right->sa_family) { + return kr_error(EFAULT); + } + if (left->sa_family == AF_INET) { + struct sockaddr_in *left_in = (struct sockaddr_in *)left; + struct sockaddr_in *right_in = (struct sockaddr_in *)right; + if (left_in->sin_addr.s_addr != right_in->sin_addr.s_addr) { + return kr_error(EFAULT); + } + } else if (left->sa_family == AF_INET6) { + struct sockaddr_in6 *left_in6 = (struct sockaddr_in6 *)left; + struct sockaddr_in6 *right_in6 = (struct sockaddr_in6 *)right; + if (memcmp(&left_in6->sin6_addr, &right_in6->sin6_addr, + sizeof(struct in6_addr)) != 0) { + return kr_error(EFAULT); + } + } else { + return kr_error(ENOENT); + } + return kr_ok(); +} + uint16_t kr_inaddr_port(const struct sockaddr *addr) { if (!addr) { diff --git a/lib/utils.h b/lib/utils.h index b990a1756..dfdb6912d 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -233,6 +233,11 @@ int kr_inaddr_len(const struct sockaddr *addr); /** Sockaddr length for given family, i.e. sizeof(struct sockaddr_in*). */ KR_EXPORT KR_PURE int kr_sockaddr_len(const struct sockaddr *addr); +/** Compare two given sockaddr. + * return 0 - addresses are equal, error code otherwise. + */ +KR_EXPORT KR_PURE +int kr_sockaddr_cmp(const struct sockaddr *left, const struct sockaddr *right); /** Port. */ KR_EXPORT KR_PURE uint16_t kr_inaddr_port(const struct sockaddr *addr); -- 2.47.2