From 201c3516e20e2c820f496e3ef7f454e4ceba7971 Mon Sep 17 00:00:00 2001 From: Karel Slany <karel.slany@nic.cz> Date: Wed, 11 May 2016 10:05:25 +0200 Subject: [PATCH] Added code trying to obtain client IP address from libuv UDP handle. --- daemon/worker.c | 30 ++++++++++++++++---- lib/cookies/control.c | 66 ++++++++++++++++++++++++++++++------------- lib/cookies/control.h | 12 ++++---- 3 files changed, 78 insertions(+), 30 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index 436bfd1a8..94fa25aa0 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -440,18 +440,36 @@ static void on_write(uv_write_t *req, int status) req_release(worker, (struct req *)req); } -/** UpdateDNS cookie data in */ -static bool subreq_update_cookies(struct sockaddr *addr, knot_pkt_t *pkt) +/** Update DNS cookie data in packet. */ +static bool subreq_update_cookies(uv_udp_t *handle, struct sockaddr *srvr_addr, + knot_pkt_t *pkt) { - assert(addr); + assert(handle); + assert(srvr_addr); assert(pkt); + + /* Cookies disabled or packet has no ENDS section. */ if (!kr_cookies_control.enabled || !pkt->opt_rr) { return true; } - kr_pkt_put_cookie(&kr_cookies_control, addr, pkt); + /* 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. */ + + 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; + } + + kr_request_put_cookie(&kr_cookies_control, + (struct sockaddr*) sockaddr_ptr, srvr_addr, pkt); - /*TODO */ return true; } @@ -476,7 +494,7 @@ static int qr_task_send(struct qr_task *task, uv_handle_t *handle, struct sockad } if (handle->type == UV_UDP) { /* Update DNS cookies data. */ - subreq_update_cookies(addr, pkt); + subreq_update_cookies((uv_udp_t *) handle, addr, pkt); uv_buf_t buf = { (char *)pkt->wire, pkt->size }; send_req->as.send.data = task; diff --git a/lib/cookies/control.c b/lib/cookies/control.c index 582b9c58c..55623c402 100644 --- a/lib/cookies/control.c +++ b/lib/cookies/control.c @@ -69,8 +69,9 @@ static int opt_rr_add_cookies(knot_rrset_t *opt_rr, } int prepare_client_cookie(uint8_t cc[KNOT_OPT_COOKIE_CLNT], - const void *srvr_addr, - const struct secret_quantity *csq) + const void *clnt_addr, + const void *srvr_addr, + const struct secret_quantity *csq) { assert(cc); assert(srvr_addr); @@ -81,27 +82,53 @@ int prepare_client_cookie(uint8_t cc[KNOT_OPT_COOKIE_CLNT], /* According to the draft (section A.1) the recommended sequence is * client IP address | server IP address , client secret. */ - int addr_family = ((struct sockaddr *) srvr_addr)->sa_family; - if (addr_family == AF_INET) { - srvr_addr = &((struct sockaddr_in *) srvr_addr)->sin_addr; - } else if (addr_family == AF_INET6) { - srvr_addr = &((struct sockaddr_in6 *) srvr_addr)->sin6_addr; - } else { - assert(0); - return kr_error(EINVAL); + if (clnt_addr) { + int addr_family = ((struct sockaddr *) clnt_addr)->sa_family; + if (addr_family == AF_INET) { + clnt_addr = &((struct sockaddr_in *) clnt_addr)->sin_addr; + } else if (addr_family == AF_INET6) { + clnt_addr = &((struct sockaddr_in6 *) clnt_addr)->sin6_addr; + } else { + //assert(0); + //return kr_error(EINVAL); + addr_family = AF_UNSPEC; + DEBUG_MSG(NULL, "%s\n", "could not obtain client IP address for client cookie"); + } + + if (addr_family != AF_UNSPEC) { + WITH_DEBUG { + char ns_str[INET6_ADDRSTRLEN]; + inet_ntop(addr_family, clnt_addr, ns_str, sizeof(ns_str)); + DEBUG_MSG(NULL, "adding client IP address '%s' into client cookie\n", ns_str); + } + } } - WITH_DEBUG { - char ns_str[INET6_ADDRSTRLEN]; - inet_ntop(addr_family, srvr_addr, ns_str, sizeof(ns_str)); - DEBUG_MSG(NULL, "adding server address '%s' into client cookie\n", ns_str); + if (srvr_addr) { + int addr_family = ((struct sockaddr *) srvr_addr)->sa_family; + if (addr_family == AF_INET) { + srvr_addr = &((struct sockaddr_in *) srvr_addr)->sin_addr; + } else if (addr_family == AF_INET6) { + srvr_addr = &((struct sockaddr_in6 *) srvr_addr)->sin6_addr; + } else { + addr_family = AF_UNSPEC; + DEBUG_MSG(NULL, "%s\n", "could not obtain server IP address for client cookie"); + } + + if (addr_family != AF_UNSPEC) { + WITH_DEBUG { + char ns_str[INET6_ADDRSTRLEN]; + inet_ntop(addr_family, srvr_addr, ns_str, sizeof(ns_str)); + DEBUG_MSG(NULL, "adding server address '%s' into client cookie\n", ns_str); + } + } } memcpy(cc, csq->secret, KNOT_OPT_COOKIE_CLNT); } -int kr_pkt_put_cookie(struct cookies_control *cntrl, void *sockaddr, - knot_pkt_t *pkt) +int kr_request_put_cookie(struct cookies_control *cntrl, void *clnt_sockaddr, + void *srvr_sockaddr, knot_pkt_t *pkt) { assert(cntrl); assert(pkt); @@ -116,7 +143,8 @@ int kr_pkt_put_cookie(struct cookies_control *cntrl, void *sockaddr, return kr_error(EINVAL); } - int ret = prepare_client_cookie(cc, sockaddr, cntrl->client); + int ret = prepare_client_cookie(cc, clnt_sockaddr, srvr_sockaddr, + cntrl->client); /* Reclaim reserved size. */ ret = knot_pkt_reclaim(pkt, knot_edns_wire_size(pkt->opt_rr)); @@ -124,8 +152,8 @@ int kr_pkt_put_cookie(struct cookies_control *cntrl, void *sockaddr, return ret; } - /* TODO -- generate cleitn cookie from client address, server address - * and secret quentity. */ + /* TODO -- generate client cookie from client address, server address + * and secret quantity. */ ret = opt_rr_add_cookies(pkt->opt_rr, cc, NULL, 0, &pkt->mm); /* Write to packet. */ diff --git a/lib/cookies/control.h b/lib/cookies/control.h index f204ee728..dedc094c7 100644 --- a/lib/cookies/control.h +++ b/lib/cookies/control.h @@ -41,11 +41,13 @@ KR_EXPORT extern struct cookies_control kr_cookies_control; /** - * Insert a DNS cookie into the packet. + * Insert a DNS cookie into query packet. * @note The packet must already contain ENDS section. - * @param cntrl Cookie control structure. - * @param pkt Packet. + * @param cntrl Cookie control structure. + * @param clnt_sockaddr Client address. + * @param srvr_sockaddr Server address. + * @param pkt DNS request packet. */ KR_EXPORT -int kr_pkt_put_cookie(struct cookies_control *cntrl, void *sockaddr, - knot_pkt_t *pkt); +int kr_request_put_cookie(struct cookies_control *cntrl, void *clnt_sockaddr, + void *srvr_sockaddr, knot_pkt_t *pkt); -- GitLab