From 5248b46c9517f1a9a5c31d4d5e42a9a08fc0cc5c Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Sat, 24 Jun 2017 11:26:27 -0400 Subject: [PATCH] [core] sock_addr_from_str_hints reusable name res [core] sock_addr_from_str_hints() reusable name resolution func --- src/base.h | 2 +- src/inet_ntop_cache.c | 148 ++++++++++++++++++++++++++++++++++++++++++ src/inet_ntop_cache.h | 11 +++- src/network.c | 132 +++---------------------------------- 4 files changed, 168 insertions(+), 125 deletions(-) diff --git a/src/base.h b/src/base.h index b13208b0..1ba123ab 100644 --- a/src/base.h +++ b/src/base.h @@ -111,7 +111,7 @@ typedef struct { } fcgi_connections; -typedef union { +typedef union sock_addr { #ifdef HAVE_IPV6 struct sockaddr_in6 ipv6; #endif diff --git a/src/inet_ntop_cache.c b/src/inet_ntop_cache.c index e4a9efd7..c8b9f633 100644 --- a/src/inet_ntop_cache.c +++ b/src/inet_ntop_cache.c @@ -2,11 +2,15 @@ #include "inet_ntop_cache.h" #include "base.h" +#include "log.h" #include "sys-socket.h" #include #include #include +#ifndef _WIN32 +#include +#endif unsigned short sock_addr_get_port (const sock_addr *addr) @@ -100,6 +104,150 @@ int sock_addr_inet_ntop_append_buffer(buffer *b, const sock_addr *addr) } +int sock_addr_from_str_hints(server *srv, sock_addr *addr, socklen_t *len, const char *str, int family, unsigned short port) +{ + /*(note: name resolution here is *blocking*)*/ + switch(family) { + #ifdef HAVE_IPV6 + case AF_INET6: + memset(addr, 0, sizeof(struct sockaddr_in6)); + addr->ipv6.sin6_family = AF_INET6; + if (0 == strcmp(str, "::")) { + addr->ipv6.sin6_addr = in6addr_any; + } + else if (0 == strcmp(str, "::1")) { + addr->ipv6.sin6_addr = in6addr_loopback; + } + else { + struct addrinfo hints, *res; + int r; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (0 != (r = getaddrinfo(str, NULL, &hints, &res))) { + hints.ai_family = AF_INET; + if ( + #ifdef EAI_ADDRFAMILY + EAI_ADDRFAMILY == r && + #endif + 0 == getaddrinfo(str, NULL, &hints, &res)) { + memcpy(addr, res->ai_addr, res->ai_addrlen); + addr->ipv4.sin_family = AF_INET; + addr->ipv4.sin_port = htons(port); + *len = sizeof(struct sockaddr_in); + /*assert(*len == res->ai_addrlen);*/ + freeaddrinfo(res); + return 1; + } + + log_error_write(srv, __FILE__, __LINE__, + "sssss", "getaddrinfo failed: ", + gai_strerror(r), "'", str, "'"); + + return 0; + } + + memcpy(addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + } + addr->ipv6.sin6_port = htons(port); + *len = sizeof(struct sockaddr_in6); + return 1; + #endif + case AF_INET: + memset(addr, 0, sizeof(struct sockaddr_in)); + addr->ipv4.sin_family = AF_INET; + if (0 == strcmp(str, "0.0.0.0")) { + addr->ipv4.sin_addr.s_addr = htonl(INADDR_ANY); + } + else if (0 == strcmp(str, "127.0.0.1")) { + addr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + else { + #ifdef HAVE_INET_PTON + /*(reuse HAVE_INET_PTON for presence of getaddrinfo())*/ + struct addrinfo hints, *res; + int r; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (0 != (r = getaddrinfo(str, NULL, &hints, &res))) { + log_error_write(srv, __FILE__, __LINE__, + "sssss", "getaddrinfo failed: ", + gai_strerror(r), "'", str, "'"); + return 0; + } + + memcpy(addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + #else + struct hostent *he = gethostbyname(str); + if (NULL == he) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "gethostbyname failed:", h_errno, str); + return 0; + } + + if (he->h_addrtype != AF_INET) { + log_error_write(srv, __FILE__, __LINE__, "sd", + "addr-type != AF_INET:", he->h_addrtype); + return 0; + } + + if (he->h_length != sizeof(struct in_addr)) { + log_error_write(srv, __FILE__, __LINE__, "sd", + "addr-length != sizeof(in_addr):",he->h_length); + return 0; + } + + memcpy(&addr->ipv4.sin_addr.s_addr,he->h_addr_list[0],he->h_length); + #endif + } + addr->ipv4.sin_port = htons(port); + *len = sizeof(struct sockaddr_in); + return 1; + #ifdef HAVE_SYS_UN_H + case AF_UNIX: + memset(addr, 0, sizeof(struct sockaddr_un)); + addr->un.sun_family = AF_UNIX; + { + size_t hostlen = strlen(str) + 1; + if (hostlen > sizeof(addr->un.sun_path)) { + log_error_write(srv, __FILE__, __LINE__, "sS", + "unix socket filename too long:", str); + /*errno = ENAMETOOLONG;*/ + return 0; + } + memcpy(addr->un.sun_path, str, hostlen); + #if defined(SUN_LEN) + *len = SUN_LEN(&addr->un); + #else + /* stevens says: */ + *len = hostlen + sizeof(addr->un.sun_family); + #endif + } + return 1; + #else + case AF_UNIX: + log_error_write(srv, __FILE__, __LINE__, "s", + "unix domain sockets are not supported."); + return 0; + #endif + default: + log_error_write(srv, __FILE__, __LINE__, "sd", + "address family unsupported:", family); + /*errno = EAFNOSUPPORT;*/ + return 0; + } +} + + const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) { #ifdef HAVE_IPV6 typedef struct { diff --git a/src/inet_ntop_cache.h b/src/inet_ntop_cache.h index 23cff464..37db3b94 100644 --- a/src/inet_ntop_cache.h +++ b/src/inet_ntop_cache.h @@ -2,7 +2,14 @@ #define _INET_NTOP_CACHE_H_ #include "first.h" -#include "base.h" +#include +#include "sys-socket.h" +#include "buffer.h" + +struct server; +typedef struct server server; +union sock_addr; +typedef union sock_addr sock_addr; unsigned short sock_addr_get_port (const sock_addr *addr); @@ -12,6 +19,8 @@ const char * sock_addr_inet_ntop(const sock_addr *addr, char *buf, socklen_t sz) int sock_addr_inet_ntop_copy_buffer(buffer *b, const sock_addr *addr); int sock_addr_inet_ntop_append_buffer(buffer *b, const sock_addr *addr); +int sock_addr_from_str_hints(server *srv, sock_addr *addr, socklen_t *len, const char *str, int family, unsigned short port); + const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr); #endif diff --git a/src/network.c b/src/network.c index ff584bf2..1ee43bf0 100644 --- a/src/network.c +++ b/src/network.c @@ -7,13 +7,11 @@ #include "plugin.h" #include "joblist.h" #include "configfile.h" +#include "inet_ntop_cache.h" #include "network_backends.h" #include "sys-mmap.h" #include "sys-socket.h" -#ifndef _WIN32 -#include -#endif #include #include @@ -107,7 +105,7 @@ static int network_server_init(server *srv, buffer *host_token, size_t sidx) { buffer_copy_buffer(srv_socket->srv_token, host_token); b = buffer_init(); - buffer_copy_buffer(b, host_token); + buffer_copy_buffer(b, host_token); /*(allocates b->ptr even if host_token is NULL)*/ host = b->ptr; @@ -155,134 +153,22 @@ static int network_server_init(server *srv, buffer *host_token, size_t sidx) { } } - if (*host == '\0') host = NULL; - #ifdef HAVE_IPV6 if (s->use_ipv6) { srv_socket->addr.plain.sa_family = AF_INET6; } #endif - switch(srv_socket->addr.plain.sa_family) { -#ifdef HAVE_IPV6 - case AF_INET6: - memset(&srv_socket->addr, 0, sizeof(struct sockaddr_in6)); - srv_socket->addr.ipv6.sin6_family = AF_INET6; - if (host == NULL) { - srv_socket->addr.ipv6.sin6_addr = in6addr_any; + if (*host == '\0') { + if (srv_socket->addr.plain.sa_family == AF_INET6) { log_error_write(srv, __FILE__, __LINE__, "s", "warning: please use server.use-ipv6 only for hostnames, not without server.bind / empty address; your config will break if the kernel default for IPV6_V6ONLY changes"); - } else { - struct addrinfo hints, *res; - int r; - - memset(&hints, 0, sizeof(hints)); - - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) { - hints.ai_family = AF_INET; - if ( - #ifdef EAI_ADDRFAMILY - EAI_ADDRFAMILY == r && - #endif - 0 == getaddrinfo(host, NULL, &hints, &res)) { - memcpy(&srv_socket->addr.ipv4, res->ai_addr, res->ai_addrlen); - srv_socket->addr.ipv4.sin_family = AF_INET; - srv_socket->addr.ipv4.sin_port = htons(port); - addr_len = sizeof(struct sockaddr_in); - /*assert(addr_len == res->ai_addrlen);*/ - freeaddrinfo(res); - break; - } - - log_error_write(srv, __FILE__, __LINE__, - "sssss", "getaddrinfo failed: ", - gai_strerror(r), "'", host, "'"); - - goto error_free_socket; - } - - memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen); - - freeaddrinfo(res); - } - srv_socket->addr.ipv6.sin6_port = htons(port); - addr_len = sizeof(struct sockaddr_in6); - break; -#endif - case AF_INET: - memset(&srv_socket->addr, 0, sizeof(struct sockaddr_in)); - srv_socket->addr.ipv4.sin_family = AF_INET; - if (host == NULL) { - srv_socket->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY); - } else { -#ifdef HAVE_INET_PTON /*(reuse HAVE_INET_PTON for presence of getaddrinfo())*/ - struct addrinfo hints, *res; - int r; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) { - log_error_write(srv, __FILE__, __LINE__, - "sssss", "getaddrinfo failed: ", - gai_strerror(r), "'", host, "'"); - goto error_free_socket; - } - - memcpy(&(srv_socket->addr.ipv4), res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); -#else - struct hostent *he; - if (NULL == (he = gethostbyname(host))) { - log_error_write(srv, __FILE__, __LINE__, - "sds", "gethostbyname failed: ", - h_errno, host); - goto error_free_socket; - } - - if (he->h_addrtype != AF_INET) { - log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype); - goto error_free_socket; - } - - if (he->h_length != sizeof(struct in_addr)) { - log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length); - goto error_free_socket; - } - - memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length); -#endif - } - srv_socket->addr.ipv4.sin_port = htons(port); - addr_len = sizeof(struct sockaddr_in); - break; -#ifdef HAVE_SYS_UN_H - case AF_UNIX: - memset(&srv_socket->addr, 0, sizeof(struct sockaddr_un)); - srv_socket->addr.un.sun_family = AF_UNIX; - { - size_t hostlen = strlen(host) + 1; - if (hostlen > sizeof(srv_socket->addr.un.sun_path)) { - log_error_write(srv, __FILE__, __LINE__, "sS", "unix socket filename too long:", host); - goto error_free_socket; - } - memcpy(srv_socket->addr.un.sun_path, host, hostlen); - -#if defined(SUN_LEN) - addr_len = SUN_LEN(&srv_socket->addr.un); -#else - /* stevens says: */ - addr_len = hostlen + sizeof(srv_socket->addr.un.sun_family); -#endif + host = "::"; + } else if (srv_socket->addr.plain.sa_family == AF_INET) { + host = "0.0.0.0"; } + } - break; -#endif - default: + if (1 != sock_addr_from_str_hints(srv, &srv_socket->addr, &addr_len, host, srv_socket->addr.plain.sa_family, port)) { goto error_free_socket; }