From 6f0371c46f6f9ef4cffe07631e72a95ccd83e33d Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Sun, 29 Jan 2023 20:31:27 +0100 Subject: [PATCH] Use getaddrinfo/getnameinfo instead of deprecated methods --- src/lib/proxy.c | 48 +++----------------- src/lib/sock.c | 96 ++++++++++++++++++++++++++++++++++++++- src/lib/sock.h | 6 +++ src/worker/tcp_acceptor.c | 29 +----------- 4 files changed, 107 insertions(+), 72 deletions(-) diff --git a/src/lib/proxy.c b/src/lib/proxy.c index cbb7df3..481e06b 100644 --- a/src/lib/proxy.c +++ b/src/lib/proxy.c @@ -19,7 +19,6 @@ #include #include #include -#include #include static SSL_CTX *proxy_ctx = NULL; @@ -303,48 +302,10 @@ int proxy_response_header(http_req *req, http_res *res, host_config_t *conf) { static int proxy_connect(proxy_ctx_t *proxy, host_config_t *conf, http_res *res, http_status_ctx *ctx, char *err_msg) { char err_buf[256], addr_buf[1024]; + info(BLUE_STR "Connecting to " BLD_STR "[%s]:%i" CLR_STR BLUE_STR "...", conf->proxy.hostname, conf->proxy.port); + int fd; - if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) == -1) { - error("Unable to create socket"); - res->status = http_get_status(500); - ctx->origin = INTERNAL; - return -1; - } - sock_init(&proxy->proxy, fd, 0); - - if (sock_set_socket_timeout(&proxy->proxy, 1) != 0 || sock_set_timeout(&proxy->proxy, SERVER_TIMEOUT_INIT) != 0) { - res->status = http_get_status(500); - ctx->origin = INTERNAL; - error("Unable to set timeout for reverse proxy socket"); - sprintf(err_msg, "Unable to set timeout for reverse proxy socket: %s", error_str(errno, err_buf, sizeof(err_buf))); - return -1; - } - - struct hostent *host_ent = gethostbyname2(conf->proxy.hostname, AF_INET6); - if (host_ent == NULL) { - host_ent = gethostbyname2(conf->proxy.hostname, AF_INET); - if (host_ent == NULL) { - res->status = http_get_status(502); - ctx->origin = SERVER_REQ; - error("Unable to connect to server: Name or service not known"); - sprintf(err_msg, "Unable to connect to server: Name or service not known."); - return -1; - } - } - - struct sockaddr_in6 address = {.sin6_family = AF_INET6, .sin6_port = htons(conf->proxy.port)}; - if (host_ent->h_addrtype == AF_INET6) { - memcpy(&address.sin6_addr, host_ent->h_addr_list[0], host_ent->h_length); - } else if (host_ent->h_addrtype == AF_INET) { - unsigned char addr[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0}; - memcpy(addr + 12, host_ent->h_addr_list[0], host_ent->h_length); - memcpy(&address.sin6_addr, addr, 16); - } - - inet_ntop(address.sin6_family, (void *) &address.sin6_addr, addr_buf, sizeof(addr_buf)); - - info(BLUE_STR "Connecting to " BLD_STR "[%s]:%i" CLR_STR BLUE_STR "...", addr_buf, conf->proxy.port); - if (connect(proxy->proxy.socket, (struct sockaddr *) &address, sizeof(address)) < 0) { + if ((fd = sock_connect(conf->proxy.hostname, conf->proxy.port, SERVER_TIMEOUT_INIT, addr_buf, sizeof(addr_buf))) == -1) { if (errno == ETIMEDOUT || errno == EINPROGRESS) { res->status = http_get_status(504); ctx->origin = SERVER_REQ; @@ -360,6 +321,8 @@ static int proxy_connect(proxy_ctx_t *proxy, host_config_t *conf, http_res *res, return -1; } + sock_init(&proxy->proxy, fd, 0); + if (sock_set_timeout(&proxy->proxy, SERVER_TIMEOUT) != 0) { res->status = http_get_status(500); ctx->origin = INTERNAL; @@ -389,6 +352,7 @@ static int proxy_connect(proxy_ctx_t *proxy, host_config_t *conf, http_res *res, proxy->initialized = 1; proxy->cnx_s = clock_micros(); proxy->host = conf->name; + info(BLUE_STR "Established new connection with " BLD_STR "[%s]:%i", addr_buf, conf->proxy.port); return 0; diff --git a/src/lib/sock.c b/src/lib/sock.c index 4fafd8a..eba4b83 100644 --- a/src/lib/sock.c +++ b/src/lib/sock.c @@ -9,6 +9,7 @@ #include "sock.h" #include "utils.h" #include "error.h" +#include "../logger.h" #include #include @@ -18,8 +19,9 @@ #include #include #include +#include -static void ssl_error(unsigned long err) { +static void sock_ssl_error(unsigned long err) { if (err == SSL_ERROR_NONE) { errno = 0; } else if (err == SSL_ERROR_SYSCALL) { @@ -32,7 +34,18 @@ static void ssl_error(unsigned long err) { } void sock_error(sock *s, int ret) { - ssl_error(SSL_get_error(s->ssl, ret)); + sock_ssl_error(SSL_get_error(s->ssl, ret)); +} + +int sock_gai_error(int ret) { + if (ret == 0) { + errno = 0; + } else if (ret == EAI_SYSTEM) { + // errno already set + } else { + error_gai(ret); + } + return -1; } const char *sock_error_str(unsigned long err) { @@ -78,6 +91,85 @@ int sock_init(sock *s, int fd, int flags) { return 0; } +int sock_connect(const char *hostname, unsigned short port, double timeout_sec, char *addr_buf, size_t addr_buf_size) { + char buf[INET6_ADDRSTRLEN + 1]; + int ret, fd, e = 0; + long timeout_micros = (long) (timeout_sec * 1000000L); + struct addrinfo *result, *rp, + hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = 0, + .ai_flags = 0, + }; + + if (addr_buf && addr_buf_size > 1) + addr_buf[0] = 0; + + if ((ret = getaddrinfo(hostname, NULL, &hints, &result)) != 0) + return sock_gai_error(ret); + + for (rp = result; rp != NULL; rp = rp->ai_next) { + switch (rp->ai_family) { + case AF_INET: + ((struct sockaddr_in *) rp->ai_addr)->sin_port = htons(port); + inet_ntop(rp->ai_family, &((struct sockaddr_in *) rp->ai_addr)->sin_addr, buf, addr_buf_size); + break; + case AF_INET6: + ((struct sockaddr_in6 *) rp->ai_addr)->sin6_port = htons(port); + inet_ntop(rp->ai_family, &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr, buf, addr_buf_size); + break; + } + + debug("Trying [%s]:%i", buf, port); + + if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1) { + if (e == 0) { + e = errno; + } else if (e != errno) { + e = -1; + } + continue; + } + + if (sock_set_socket_timeout_micros(fd, timeout_micros, timeout_micros) == -1) { + close(fd); + return -1; + } + + if (connect(fd, rp->ai_addr, rp->ai_addrlen) == -1) { + e = errno; + close(fd); + continue; + } + + break; + } + + freeaddrinfo(result); + + if (addr_buf && addr_buf_size > 1 && addr_buf[0] == 0) + strncpy(addr_buf, buf, addr_buf_size); + + errno = e; + return (e == 0) ? fd : -1; +} + +int sock_reverse_lookup(const sock *s, char *host, size_t host_size) { + memset(host, 0, host_size); + + int ret; + if ((ret = getnameinfo(&s->_addr.sock, sizeof(s->_addr), host, host_size, NULL, 0, 0)) != 0) { + if (ret == EAI_NONAME) { + return 0; + } else { + return sock_gai_error(ret); + } + } + + return 0; +} + int sock_set_socket_timeout_micros(int fd, long recv_micros, long send_micros) { struct timeval recv_to = {.tv_sec = recv_micros / 1000000, .tv_usec = recv_micros % 1000000}, send_to = {.tv_sec = send_micros / 1000000, .tv_usec = send_micros % 1000000}; diff --git a/src/lib/sock.h b/src/lib/sock.h index db1ee9b..043e404 100644 --- a/src/lib/sock.h +++ b/src/lib/sock.h @@ -38,6 +38,12 @@ const char *sock_error_str(unsigned long err); int sock_init(sock *s, int fd, int enc); +int sock_connect(const char *hostname, unsigned short port, double timeout_sec, char *addr_buf, size_t addr_buf_size); + +int sock_reverse_lookup(const sock *s, char *host, size_t host_size); + +int sock_init_addr_str(const sock *s, char *c_addr, size_t c_addr_size, char *s_addr, size_t s_addr_size); + int sock_set_socket_timeout_micros(int fd, long recv_micros, long send_micros); int sock_set_socket_timeout(sock *s, double sec); diff --git a/src/worker/tcp_acceptor.c b/src/worker/tcp_acceptor.c index c20419f..24794d1 100644 --- a/src/worker/tcp_acceptor.c +++ b/src/worker/tcp_acceptor.c @@ -28,32 +28,6 @@ void tcp_acceptor_func(client_ctx_t *ctx) { } } -static int dig(const char *addr, char *host, size_t host_size) { - char buf[1024]; - FILE *out; - int ret; - - sprintf(buf, "dig +short +time=1 -x %s", addr); - if ((out = popen(buf, "r")) == NULL) { - error("Unable to start dig: %s"); - return -1; - } - - unsigned long read = fread(buf, 1, sizeof(buf), out); - if ((ret = pclose(out)) != 0) { - error("Dig terminated with exit code %i", ret); - return -1; - } - - char *ptr = memchr(buf, '\n', read); - if (ptr == buf || ptr == NULL) return -1; - - ptr[-1] = 0; - strncpy(host, buf, host_size); - - return 0; -} - static int tcp_acceptor(client_ctx_t *ctx) { struct sockaddr_in6 server_addr; @@ -84,8 +58,7 @@ static int tcp_acceptor(client_ctx_t *ctx) { sock *client = &ctx->socket; ctx->cnx_s = clock_micros(); - ctx->host[0] = 0; - dig(ctx->socket.addr, ctx->host, sizeof(ctx->host)); + sock_reverse_lookup(&ctx->socket, ctx->host, sizeof(ctx->host)); ctx->cc[0] = 0; geoip_lookup_country(&client->_addr.sock, ctx->cc);