From 078b689f97d30c68bf4a5d5930e95bf96b6f7384 Mon Sep 17 00:00:00 2001 From: Tom Carroll <34632752+tomc797@users.noreply.github.com> Date: Tue, 13 Jun 2023 21:51:20 -0700 Subject: [PATCH] Handle case of host == NULL The fix addresses two defects. The getaddrinfo interface contract allowed for host == NULL, but Ziti_resolve assumed host != NULL. zitify nc -l 9999 would trigger a fault. Additionally, hints was accessed without checking to ensure it was NULL. Lastly, Ziti_resolve would leak res and addr if the function wasn't successful. Signed-off-by: Tom Carroll <4632752+tomc797@users.noreply.github.com> --- library/zitilib.c | 92 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/library/zitilib.c b/library/zitilib.c index c0c1982b..666e4144 100644 --- a/library/zitilib.c +++ b/library/zitilib.c @@ -1225,7 +1225,34 @@ ZITI_FUNC int Ziti_resolve(const char *host, const char *port, const struct addrinfo *hints, struct addrinfo **addrlist) { in_port_t portnum = port ? (in_port_t) strtol(port, NULL, 10) : 0; ZITI_LOG(DEBUG, "host[%s] port[%s]", host, port); - struct addrinfo *res = calloc(1, sizeof(struct addrinfo)); + + /** + * Linux and FreeBSD freeaddrinfo(ai) frees ai->canonname and ai, but not ai->ai_addr. + * ai is allocated large enough to carry the sockaddr + */ + union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in in4; + struct sockaddr_in6 in6; + }; + + struct result_storage { + struct addrinfo addrinfo; + union sockaddr_union sockaddr; + } *store = calloc(1, sizeof *store); + + if (!store) + goto error; + + struct addrinfo *res = &store->addrinfo; + union sockaddr_union *addr = &store->sockaddr; + + res->ai_family = AF_UNSPEC; + res->ai_socktype = 0; + res->ai_protocol = 0; + + addr->sa.sa_family = AF_UNSPEC; + if (hints) { res->ai_socktype = hints->ai_socktype; switch (hints->ai_socktype) { @@ -1239,27 +1266,36 @@ int Ziti_resolve(const char *host, const char *port, const struct addrinfo *hint res->ai_protocol = 0; break; default: // no other protocols are supported - return -1; + goto error; + } + + switch (hints->ai_family) { + case AF_INET: + case AF_INET6: + case AF_UNSPEC: + res->ai_family = hints->ai_family; + break; + default: // unsupported address family + goto error; } } - struct sockaddr_in *addr4 = calloc(1, sizeof(struct sockaddr_in6)); - int rc = 0; - if ((rc = uv_ip4_addr(host, portnum, addr4)) == 0) { - ZITI_LOG(DEBUG, "host[%s] port[%s] rc = %d", host, port, rc); + if ((res->ai_family == AF_UNSPEC || res->ai_family == AF_INET) + && uv_ip4_addr(host ? host : "127.0.0.1", portnum, &addr->in4) == 0) { + ZITI_LOG(DEBUG, "host[%s] port[%s]", host, port); res->ai_family = AF_INET; - res->ai_addr = (struct sockaddr *) addr4; - res->ai_addrlen = sizeof(struct sockaddr_in); - + res->ai_addr = &addr->sa; + res->ai_addrlen = sizeof addr->in4; *addrlist = res; return 0; - } else if (uv_ip6_addr(host, portnum, (struct sockaddr_in6 *) addr4) == 0) { - ZITI_LOG(INFO, "host[%s] port[%s] rc = %d", host, port, rc); + } else if ((res->ai_family == AF_UNSPEC || res->ai_family == AF_INET6) + && uv_ip6_addr(host ? host : "::1", portnum, &addr->in6) == 0) { + ZITI_LOG(INFO, "host[%s] port[%s]", host, port); res->ai_family = AF_INET6; - res->ai_addr = (struct sockaddr *) addr4; - res->ai_addrlen = sizeof(struct sockaddr_in6); + res->ai_addr = &addr->sa; + res->ai_addrlen = sizeof addr->in6; *addrlist = res; return 0; } @@ -1273,14 +1309,14 @@ int Ziti_resolve(const char *host, const char *port, const struct addrinfo *hint tlsuv_parse_url(&url, ctrl); if (strncmp(host, url.hostname, url.hostname_len) == 0) { - return -1; + goto error; } if (wrap->ztx) { MODEL_MAP_FOR(chit, wrap->ztx->channels) { ziti_channel_t *ch = model_map_it_value(chit); if (strcmp(ch->host, host) == 0) { - return -1; + goto error; } } } @@ -1300,21 +1336,25 @@ int Ziti_resolve(const char *host, const char *port, const struct addrinfo *hint int err = await_future(f); set_error(err); - if (err == 0) { - addr4->sin_family = AF_INET; - addr4->sin_port = htons(portnum); - addr4->sin_addr.s_addr = (in_addr_t)(uintptr_t)f->result; + if (err != 0) + goto error; - res->ai_family = AF_INET; - res->ai_addr = (struct sockaddr *) addr4; - res->ai_socktype = hints->ai_socktype; + addr->in4.sin_family = AF_INET; + addr->in4.sin_port = htons(portnum); + addr->in4.sin_addr.s_addr = (in_addr_t)(uintptr_t)f->result; + + res->ai_family = AF_INET; + res->ai_addr = &addr->sa; + res->ai_addrlen = sizeof addr->in4; + *addrlist = res; - res->ai_addrlen = sizeof(*addr4); - *addrlist = res; - } destroy_future(f); - return err == 0 ? 0 : -1; + return 0; + +error: + free(store); + return -1; } int Ziti_check_socket(ziti_socket_t fd) {