[core] sock_addr_from_str_hints reusable name res

[core] sock_addr_from_str_hints() reusable name resolution func
This commit is contained in:
Glenn Strauss 2017-06-24 11:26:27 -04:00
parent 9e75b81982
commit 5248b46c95
4 changed files with 168 additions and 125 deletions

View File

@ -111,7 +111,7 @@ typedef struct {
} fcgi_connections;
typedef union {
typedef union sock_addr {
#ifdef HAVE_IPV6
struct sockaddr_in6 ipv6;
#endif

View File

@ -2,11 +2,15 @@
#include "inet_ntop_cache.h"
#include "base.h"
#include "log.h"
#include "sys-socket.h"
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#ifndef _WIN32
#include <netdb.h>
#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 {

View File

@ -2,7 +2,14 @@
#define _INET_NTOP_CACHE_H_
#include "first.h"
#include "base.h"
#include <sys/types.h>
#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

View File

@ -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 <netdb.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
@ -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);
host = "::";
} else if (srv_socket->addr.plain.sa_family == AF_INET) {
host = "0.0.0.0";
}
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
}
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;
}