summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2017-10-29 01:23:19 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2017-10-29 01:23:19 -0400
commit1367f60626bed0991f6ca718ebc1fe2f2912096b (patch)
tree8df0011eb75516d8e7ecdd7040facb2ce362806d
parentcaab4cdf8a37dbbd660249a4cec8f646239b4ae2 (diff)
downloadlighttpd-git-1367f60626bed0991f6ca718ebc1fe2f2912096b.tar.gz
[core] isolate sock_addr manipulation
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/Makefile.am11
-rw-r--r--src/SConscript7
-rw-r--r--src/base.h13
-rw-r--r--src/configfile-glue.c75
-rw-r--r--src/connections-glue.c2
-rw-r--r--src/connections.c2
-rw-r--r--src/gw_backend.c4
-rw-r--r--src/http-header-glue.c26
-rw-r--r--src/inet_ntop_cache.c457
-rw-r--r--src/inet_ntop_cache.h16
-rw-r--r--src/meson.build3
-rw-r--r--src/mod_evasive.c25
-rw-r--r--src/mod_extforward.c18
-rw-r--r--src/mod_proxy.c40
-rw-r--r--src/network.c36
-rw-r--r--src/request.c2
-rw-r--r--src/server.c39
-rw-r--r--src/sock_addr.c685
-rw-r--r--src/sock_addr.h51
-rw-r--r--src/sys-socket.h3
-rw-r--r--src/test_configfile.c17
22 files changed, 817 insertions, 719 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e7a4bf87..2e7c5948 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -555,12 +555,13 @@ set(COMMON_SRC
fdevent_solaris_devpoll.c fdevent_solaris_port.c
fdevent_freebsd_kqueue.c
data_config.c
- inet_ntop_cache.c crc32.c
+ crc32.c
connections-glue.c
configfile-glue.c
http-header-glue.c
http_auth.c
http_vhostdb.c
+ sock_addr.c
splaytree.c
rand.c
status_counter.c safe_memclear.c
@@ -587,6 +588,7 @@ add_executable(lighttpd
server.c
response.c
connections.c
+ inet_ntop_cache.c
network.c
network_darwin_sendfile.c
network_freebsd_sendfile.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 4a78d7a0..c16fc449 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -67,7 +67,7 @@ common_src=base64.c buffer.c log.c \
fdevent_solaris_devpoll.c fdevent_solaris_port.c \
fdevent_freebsd_kqueue.c \
data_config.c \
- inet_ntop_cache.c crc32.c \
+ crc32.c \
connections-glue.c \
configfile-glue.c \
http-header-glue.c \
@@ -75,10 +75,13 @@ common_src=base64.c buffer.c log.c \
http_vhostdb.c \
rand.c \
request.c \
+ sock_addr.c \
splaytree.c status_counter.c \
safe_memclear.c
-src = server.c response.c connections.c network.c \
+src = server.c response.c connections.c \
+ inet_ntop_cache.c \
+ network.c \
network_write.c network_linux_sendfile.c \
network_write_mmap.c network_write_no_mmap.c \
network_freebsd_sendfile.c network_writev.c \
@@ -389,7 +392,7 @@ hdr = server.h base64.h buffer.h network.h log.h keyvalue.h \
rand.h \
sys-endian.h sys-mmap.h sys-socket.h sys-strings.h \
mod_cml.h mod_cml_funcs.h \
- safe_memclear.h splaytree.h proc_open.h status_counter.h \
+ safe_memclear.h sock_addr.h splaytree.h proc_open.h status_counter.h \
mod_magnet_cache.h
@@ -513,7 +516,7 @@ test_buffer_LDADD = $(LIBUNWIND_LIBS)
test_base64_SOURCES = test_base64.c base64.c buffer.c
test_base64_LDADD = $(LIBUNWIND_LIBS)
-test_configfile_SOURCES = test_configfile.c buffer.c array.c data_string.c keyvalue.c vector.c log.c
+test_configfile_SOURCES = test_configfile.c buffer.c array.c data_string.c keyvalue.c vector.c log.c sock_addr.c
test_configfile_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
noinst_HEADERS = $(hdr)
diff --git a/src/SConscript b/src/SConscript
index 4c2ba11a..d2bfa7d7 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -62,18 +62,21 @@ common_src = Split("base64.c buffer.c log.c \
fdevent_solaris_devpoll.c fdevent_solaris_port.c \
fdevent_freebsd_kqueue.c \
data_config.c \
- inet_ntop_cache.c crc32.c \
+ crc32.c \
connections-glue.c \
configfile-glue.c \
http-header-glue.c \
http_auth.c \
http_vhostdb.c \
+ sock_addr.c \
splaytree.c \
rand.c \
status_counter.c safe_memclear.c \
")
-src = Split("server.c response.c connections.c network.c \
+src = Split("server.c response.c connections.c \
+ inet_ntop_cache.c \
+ network.c \
network_writev.c \
network_write_mmap.c network_write_no_mmap.c \
network_write.c network_linux_sendfile.c \
diff --git a/src/base.h b/src/base.h
index 0ddae6ea..c6c88c23 100644
--- a/src/base.h
+++ b/src/base.h
@@ -23,7 +23,7 @@
#include "array.h"
#include "chunk.h"
#include "keyvalue.h"
-#include "sys-socket.h"
+#include "sock_addr.h"
#include "etag.h"
struct fdevents; /* declaration */
@@ -104,17 +104,6 @@ typedef struct {
} request_handler;
-union sock_addr {
-#ifdef HAVE_IPV6
- struct sockaddr_in6 ipv6;
-#endif
- struct sockaddr_in ipv4;
-#ifdef HAVE_SYS_UN_H
- struct sockaddr_un un;
-#endif
- struct sockaddr plain;
-};
-
/* fcgi_response_header contains ... */
#define HTTP_STATUS BV(0)
#define HTTP_CONNECTION BV(1)
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
index cacf1f9a..6f0f576e 100644
--- a/src/configfile-glue.c
+++ b/src/configfile-glue.c
@@ -5,14 +5,12 @@
#include "array.h"
#include "log.h"
#include "plugin.h"
+#include "sock_addr.h"
#include "configfile.h"
#include <string.h>
#include <stdlib.h>
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
/**
* like all glue code this file contains functions which
@@ -225,72 +223,22 @@ static const char* cond_result_to_string(cond_result_t cond_result) {
static int config_addrstr_eq_remote_ip_mask(server *srv, const char *addrstr, int nm_bits, sock_addr *rmt) {
/* special-case 0 == nm_bits to mean "all bits of the address" in addrstr */
- sock_addr val;
-#ifdef HAVE_INET_PTON
- if (1 == inet_pton(AF_INET, addrstr, &val.ipv4.sin_addr))
-#else
- if (INADDR_NONE != (val.ipv4.sin_addr = inet_addr(addrstr)))
-#endif
- {
- /* build netmask */
- uint32_t nm;
+ sock_addr addr;
+ if (1 == sock_addr_inet_pton(&addr, addrstr, AF_INET, 0)) {
if (nm_bits > 32) {
log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv4 netmask too large:", nm_bits);
return -1;
}
- nm = htonl(~((1u << (32 - (0 != nm_bits ? nm_bits : 32))) - 1));
-
- if (rmt->plain.sa_family == AF_INET) {
- return ((val.ipv4.sin_addr.s_addr & nm) == (rmt->ipv4.sin_addr.s_addr & nm));
-#ifdef HAVE_IPV6
- } else if (rmt->plain.sa_family == AF_INET6
- && IN6_IS_ADDR_V4MAPPED(&rmt->ipv6.sin6_addr)) {
- #ifdef s6_addr32
- in_addr_t x = rmt->ipv6.sin6_addr.s6_addr32[3];
- #else
- in_addr_t x;
- memcpy(&x, rmt->ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
- #endif
- return ((val.ipv4.sin_addr.s_addr & nm) == (x & nm));
-#endif
- } else {
- return 0;
- }
-#if defined(HAVE_INET_PTON) && defined(HAVE_IPV6)
- } else if (1 == inet_pton(AF_INET6, addrstr, &val.ipv6.sin6_addr)) {
+ } else if (1 == sock_addr_inet_pton(&addr, addrstr, AF_INET6, 0)) {
if (nm_bits > 128) {
log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv6 netmask too large:", nm_bits);
return -1;
}
- if (rmt->plain.sa_family == AF_INET6) {
- uint8_t *a = (uint8_t *)&val.ipv6.sin6_addr.s6_addr[0];
- uint8_t *b = (uint8_t *)&rmt->ipv6.sin6_addr.s6_addr[0];
- int match;
- do {
- match = (nm_bits >= 8)
- ? *a++ == *b++
- : (*a >> (8 - nm_bits)) == (*b >> (8 - nm_bits));
- } while (match && (nm_bits -= 8) > 0);
- return match;
- } else if (rmt->plain.sa_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED(&val.ipv6.sin6_addr)) {
- uint32_t nm =
- nm_bits < 128 ? htonl(~(~0u >> (nm_bits > 96 ? nm_bits - 96 : 0))) : ~0u;
- #ifdef s6_addr32
- in_addr_t x = val.ipv6.sin6_addr.s6_addr32[3];
- #else
- in_addr_t x;
- memcpy(&x, val.ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
- #endif
- return ((x & nm) == (rmt->ipv4.sin_addr.s_addr & nm));
- } else {
- return 0;
- }
-#endif
} else {
log_error_write(srv, __FILE__, __LINE__, "ss", "ERROR: ip addr is invalid:", addrstr);
return -1;
}
+ return sock_addr_is_addr_eq_bits(&addr, rmt, nm_bits);
}
static int config_addrbuf_eq_remote_ip_mask(server *srv, buffer *string, char *nm_slash, sock_addr *rmt) {
@@ -420,18 +368,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
switch(dc->cond) {
case CONFIG_COND_NE:
case CONFIG_COND_EQ:
- switch (srv_sock->addr.plain.sa_family) {
- case AF_INET:
- port = ntohs(srv_sock->addr.ipv4.sin_port);
- break;
- #ifdef HAVE_IPV6
- case AF_INET6:
- port = ntohs(srv_sock->addr.ipv6.sin6_port);
- break;
- #endif
- default:
- port = 0;
- }
+ port = sock_addr_get_port(&srv_sock->addr);
if (0 == port) break;
ck_colon = strchr(dc->string->ptr, ':');
val_colon = strchr(l->ptr, ':');
diff --git a/src/connections-glue.c b/src/connections-glue.c
index 8ba37c34..7c6309b7 100644
--- a/src/connections-glue.c
+++ b/src/connections-glue.c
@@ -325,7 +325,7 @@ int connection_write_chunkqueue(server *srv, connection *con, chunkqueue *cq, of
* and only if TCP socket
*/
if (cq->first && cq->first->next) {
- const int sa_family = con->srv_socket->addr.plain.sa_family;
+ const int sa_family = sock_addr_get_family(&con->srv_socket->addr);
if (sa_family == AF_INET || sa_family == AF_INET6) {
chunk *c = cq->first;
while (c->type == MEM_CHUNK && NULL != (c = c->next)) ;
diff --git a/src/connections.c b/src/connections.c
index 33eca67e..bf271bb4 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -960,7 +960,7 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
}
return NULL;
} else {
- if (cnt_addr.plain.sa_family != AF_UNIX) {
+ if (sock_addr_get_family(&cnt_addr) != AF_UNIX) {
network_accept_tcp_nagle_disable(cnt);
}
return connection_accepted(srv, srv_socket, &cnt_addr, cnt);
diff --git a/src/gw_backend.c b/src/gw_backend.c
index 8eb92608..c24332b6 100644
--- a/src/gw_backend.c
+++ b/src/gw_backend.c
@@ -23,8 +23,8 @@
#include "buffer.h"
#include "crc32.h"
#include "fdevent.h"
-#include "inet_ntop_cache.h"
#include "log.h"
+#include "sock_addr.h"
@@ -397,7 +397,7 @@ static int gw_proc_sockaddr_init(server *srv, gw_host *host, gw_proc *proc) {
/* overwrite host->host buffer with IP addr string so that
* any further use of gw_host does not block on DNS lookup */
sock_addr_inet_ntop_copy_buffer(host->host, &addr);
- host->family = addr.plain.sa_family;
+ host->family = sock_addr_get_family(&addr);
}
buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
buffer_append_string_buffer(proc->connection_name, host->host);
diff --git a/src/http-header-glue.c b/src/http-header-glue.c
index 717a73e5..1916ca66 100644
--- a/src/http-header-glue.c
+++ b/src/http-header-glue.c
@@ -7,8 +7,8 @@
#include "log.h"
#include "etag.h"
#include "http_chunk.h"
-#include "inet_ntop_cache.h"
#include "response.h"
+#include "sock_addr.h"
#include "stat_cache.h"
#include <string.h>
@@ -1321,13 +1321,9 @@ int http_cgi_headers (server *srv, connection *con, http_cgi_opts *opts, http_cg
const char *s;
size_t n;
char buf[LI_ITOSTRING_LENGTH];
- #ifdef HAVE_IPV6
- char b2[INET6_ADDRSTRLEN + 1];
- #else
- char b2[INET_ADDRSTRLEN + 1];
- #endif
sock_addr *addr;
sock_addr addrbuf;
+ char b2[INET6_ADDRSTRLEN + 1];
/* (CONTENT_LENGTH must be first for SCGI) */
if (!opts->authorizer) {
@@ -1466,23 +1462,9 @@ int http_cgi_headers (server *srv, connection *con, http_cgi_opts *opts, http_cg
rc |= cb(vdata, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
switch (addr->plain.sa_family) {
- #ifdef HAVE_IPV6
- case AF_INET6:
- if (0 ==memcmp(&addr->ipv6.sin6_addr,&in6addr_any,sizeof(in6addr_any))){
- socklen_t addrlen = sizeof(addrbuf);
- if (0 == getsockname(con->fd,(struct sockaddr *)&addrbuf,&addrlen)){
- addr = &addrbuf;
- } else {
- s = "";
- break;
- }
- }
- s = sock_addr_inet_ntop(addr, b2, sizeof(b2)-1);
- if (NULL == s) s = "";
- break;
- #endif
case AF_INET:
- if (srv_sock->addr.ipv4.sin_addr.s_addr == INADDR_ANY) {
+ case AF_INET6:
+ if (sock_addr_is_addr_wildcard(addr)) {
socklen_t addrlen = sizeof(addrbuf);
if (0 == getsockname(con->fd,(struct sockaddr *)&addrbuf,&addrlen)){
addr = &addrbuf;
diff --git a/src/inet_ntop_cache.c b/src/inet_ntop_cache.c
index 8a1625b9..868b8df2 100644
--- a/src/inet_ntop_cache.c
+++ b/src/inet_ntop_cache.c
@@ -1,461 +1,15 @@
#include "first.h"
#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>
+#include <arpa/inet.h>
#endif
-
-unsigned short sock_addr_get_port (const sock_addr *addr)
-{
- switch (addr->plain.sa_family) {
- case AF_INET:
- return ntohs(addr->ipv4.sin_port);
- #ifdef HAVE_IPV6
- case AF_INET6:
- return ntohs(addr->ipv6.sin6_port);
- #endif
- default: /* case AF_UNIX: */
- return 0;
- }
-}
-
-
-int sock_addr_inet_pton(sock_addr *addr, const char *str,
- int family, unsigned short port)
-{
- if (AF_INET == family) {
- memset(&addr->ipv4, 0, sizeof(struct sockaddr_in));
- addr->ipv4.sin_family = AF_INET;
- addr->ipv4.sin_port = htons(port);
- #if defined(HAVE_INET_ATON) /*(Windows does not provide inet_aton())*/
- return (0 != inet_aton(str, &addr->ipv4.sin_addr));
- #else
- return ((addr->ipv4.sin_addr.s_addr = inet_addr(str)) != INADDR_NONE);
- #endif
- }
- #ifdef HAVE_IPV6
- else if (AF_INET6 == family) {
- memset(&addr->ipv6, 0, sizeof(struct sockaddr_in6));
- addr->ipv6.sin6_family = AF_INET6;
- addr->ipv6.sin6_port = htons(port);
- return inet_pton(AF_INET6, str, &addr->ipv6.sin6_addr);
- }
- #endif
- else {
- errno = EAFNOSUPPORT;
- return -1;
- }
-}
-
-
-const char * sock_addr_inet_ntop(const sock_addr *addr, char *buf, socklen_t sz)
-{
- if (addr->plain.sa_family == AF_INET) {
- #if defined(HAVE_INET_PTON) /*(expect inet_ntop if inet_pton)*/
- return inet_ntop(AF_INET,(const void *)&addr->ipv4.sin_addr,buf,sz);
- #else /*(inet_ntoa() not thread-safe)*/
- return inet_ntoa(addr->ipv4.sin_addr);
- #endif
- }
- #ifdef HAVE_IPV6
- else if (addr->plain.sa_family == AF_INET6) {
- return inet_ntop(AF_INET6,(const void *)&addr->ipv6.sin6_addr,buf,sz);
- }
- #endif
- #ifdef HAVE_SYS_UN_H
- else if (addr->plain.sa_family == AF_UNIX) {
- return addr->un.sun_path;
- }
- #endif
- else {
- errno = EAFNOSUPPORT;
- return NULL;
- }
-}
-
-
-int sock_addr_inet_ntop_copy_buffer(buffer *b, const sock_addr *addr)
-{
- /*(incur cost of extra copy to avoid potential extra memory allocation)*/
- char buf[UNIX_PATH_MAX];
- const char *s = sock_addr_inet_ntop(addr, buf, sizeof(buf));
- if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
- buffer_copy_string(b, s);
- return 0;
-}
-
-
-int sock_addr_inet_ntop_append_buffer(buffer *b, const sock_addr *addr)
-{
- /*(incur cost of extra copy to avoid potential extra memory allocation)*/
- char buf[UNIX_PATH_MAX];
- const char *s = sock_addr_inet_ntop(addr, buf, sizeof(buf));
- if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
- buffer_append_string(b, s);
- return 0;
-}
-
-
-int sock_addr_nameinfo_append_buffer(server *srv, buffer *b, const sock_addr *addr)
-{
- /*(this routine originates from
- * http-header-glue.c:http_response_redirect_to_directory())*/
- /*(note: name resolution here is *blocking*)*/
- if (AF_INET == addr->plain.sa_family) {
- struct hostent *he = gethostbyaddr((char *)&addr->ipv4.sin_addr,
- sizeof(struct in_addr), AF_INET);
- if (NULL == he) {
- log_error_write(srv, __FILE__, __LINE__,
- "SdS", "NOTICE: gethostbyaddr failed: ",
- h_errno, ", using ip-address instead");
-
- sock_addr_inet_ntop_append_buffer(b, addr);
- } else {
- buffer_append_string(b, he->h_name);
- }
- }
- #ifdef HAVE_IPV6
- else if (AF_INET6 == addr->plain.sa_family) {
- char hbuf[256];
- if (0 != getnameinfo((const struct sockaddr *)(&addr->ipv6),
- sizeof(addr->ipv6),
- hbuf, sizeof(hbuf), NULL, 0, 0)) {
- log_error_write(srv, __FILE__, __LINE__,
- "SSS", "NOTICE: getnameinfo failed: ",
- strerror(errno), ", using ip-address instead");
-
- buffer_append_string_len(b, CONST_STR_LEN("["));
- sock_addr_inet_ntop_append_buffer(b, addr);
- buffer_append_string_len(b, CONST_STR_LEN("]"));
- } else {
- buffer_append_string(b, hbuf);
- }
- }
- #endif
- else {
- log_error_write(srv, __FILE__, __LINE__,
- "S", "ERROR: unsupported address-type");
- return -1;
- }
-
- return 0;
-}
-
-
-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) {
- case AF_UNSPEC:
- if (0 == strcmp(str, "localhost")) {
- /*(special-case "localhost" to IPv4 127.0.0.1)*/
- memset(addr, 0, sizeof(struct sockaddr_in));
- addr->ipv4.sin_family = AF_INET;
- addr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- addr->ipv4.sin_port = htons(port);
- *len = sizeof(struct sockaddr_in);
- return 1;
- }
- #ifdef HAVE_IPV6
- else {
- struct addrinfo hints, *res;
- int r;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- 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);
- if (AF_INET6 == addr->plain.sa_family) {
- addr->ipv6.sin6_port = htons(port);
- *len = sizeof(struct sockaddr_in6);
- }
- else { /* AF_INET */
- addr->ipv4.sin_port = htons(port);
- *len = sizeof(struct sockaddr_in);
- }
- return 1;
- }
- #else
- /* fall through */
- #endif
- #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;
- }
-}
-
-
-int sock_addr_from_str_numeric(server *srv, sock_addr *addr, const char *str)
-{
- /*(note: does not handle port if getaddrinfo() is not available)*/
- /*(note: getaddrinfo() is stricter than inet_aton() in what is accepted)*/
- /*(this routine originates from mod_extforward.c:ipstr_to_sockaddr()*/
- #ifdef HAVE_IPV6
- struct addrinfo hints, *addrlist = NULL;
- int result;
-
- /**
- * quoting $ man getaddrinfo
- *
- * NOTES
- * AI_ADDRCONFIG, AI_ALL, and AI_V4MAPPED are available since glibc 2.3.3.
- * AI_NUMERICSERV is available since glibc 2.3.4.
- */
- #ifndef AI_NUMERICSERV
- #define AI_NUMERICSERV 0
- #endif
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
-
- errno = 0;
- result = getaddrinfo(str, NULL, &hints, &addrlist);
-
- if (result != 0) {
- log_error_write(srv, __FILE__, __LINE__, "SSSs(S)",
- "could not parse ip address ", str, " because ",
- gai_strerror(result), strerror(errno));
- } else if (addrlist == NULL) {
- log_error_write(srv, __FILE__, __LINE__, "SSS",
- "Problem in parsing ip address ", str,
- ": succeeded, but no information returned");
- result = -1;
- } else switch (addrlist->ai_family) {
- case AF_INET:
- memcpy(&addr->ipv4, addrlist->ai_addr, sizeof(addr->ipv4));
- force_assert(AF_INET == addr->plain.sa_family);
- break;
- case AF_INET6:
- memcpy(&addr->ipv6, addrlist->ai_addr, sizeof(addr->ipv6));
- force_assert(AF_INET6 == addr->plain.sa_family);
- break;
- default:
- log_error_write(srv, __FILE__, __LINE__, "SSS",
- "Problem in parsing ip address ", str,
- ": succeeded, but unknown family");
- result = -1;
- break;
- }
-
- freeaddrinfo(addrlist);
- return (0 == result);
- #else
- UNUSED(srv);
- addr->ipv4.sin_addr.s_addr = inet_addr(str);
- addr->plain.sa_family = AF_INET;
- return (addr->ipv4.sin_addr.s_addr != 0xFFFFFFFF);
- #endif
-}
-
-
-int sock_addr_from_buffer_hints_numeric(server *srv, sock_addr *addr, socklen_t *len, const buffer *b, int family, unsigned short port)
-{
- /*(this routine originates from mod_fastcgi.c and mod_scgi.c)*/
- if (buffer_string_is_empty(b)) {
- /*(preserve existing behavior (for now))*/
- /*(would be better if initialized default when reading config)*/
- memset(&addr->ipv4, 0, sizeof(struct sockaddr_in));
- addr->ipv4.sin_family = AF_INET;
- addr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- addr->ipv4.sin_port = htons(port);
- *len = sizeof(struct sockaddr_in);
- return 1;
- }
- else if (1 == sock_addr_inet_pton(addr, b->ptr, family, port)) {
- *len = (family == AF_INET)
- ? sizeof(struct sockaddr_in) /* family == AF_INET */
- : sizeof(struct sockaddr_in6); /* family == AF_INET6 */
- return 1;
- }
- #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
- else if (family == AF_INET6) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "invalid IPv6 address literal:", b);
- return 0;
- }
- #endif
- #ifndef HAVE_INET_PTON /*(preserve existing behavior (for now))*/
- else {
- struct hostent *he = gethostbyname(b->ptr);
- if (NULL == he) {
- log_error_write(srv, __FILE__, __LINE__, "sdb",
- "gethostbyname failed:", h_errno, b);
- 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;
- }
-
- memset(&addr->ipv4, 0, sizeof(struct sockaddr_in));
- memcpy(&addr->ipv4.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
- addr->ipv4.sin_family = AF_INET;
- addr->ipv4.sin_port = htons(port);
- *len = sizeof(struct sockaddr_in);
- }
- #else
- UNUSED(srv);
- #endif
-
- return 0;
-}
+#include "sock_addr.h"
const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
@@ -498,12 +52,7 @@ const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
i = ndx;
if (++ndx >= INET_NTOP_CACHE_MAX) ndx = 0;
- s =
- inet_ntop(addr->plain.sa_family,
- addr->plain.sa_family == AF_INET6 ?
- (const void *) &(addr->ipv6.sin6_addr) :
- (const void *) &(addr->ipv4.sin_addr),
- inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
+ s = sock_addr_inet_ntop(addr, inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
if (NULL == s) return "";
inet_ntop_cache[i].family = addr->plain.sa_family;
diff --git a/src/inet_ntop_cache.h b/src/inet_ntop_cache.h
index c38bbf56..027f4097 100644
--- a/src/inet_ntop_cache.h
+++ b/src/inet_ntop_cache.h
@@ -2,23 +2,7 @@
#define _INET_NTOP_CACHE_H_
#include "first.h"
-#include <sys/types.h>
-#include "sys-socket.h"
#include "base_decls.h"
-#include "buffer.h"
-
-unsigned short sock_addr_get_port (const sock_addr *addr);
-
-int sock_addr_inet_pton(sock_addr *addr, const char *str, int family, unsigned short port);
-
-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_nameinfo_append_buffer(server *srv, buffer *b, const sock_addr *addr);
-
-int sock_addr_from_buffer_hints_numeric(server *srv, sock_addr *addr, socklen_t *len, const buffer *b, int family, unsigned short port);
-int sock_addr_from_str_hints(server *srv, sock_addr *addr, socklen_t *len, const char *str, int family, unsigned short port);
-int sock_addr_from_str_numeric(server *srv, sock_addr *addr, const char *str);
const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr);
diff --git a/src/meson.build b/src/meson.build
index e3c91d2f..08a4c8b0 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -550,7 +550,6 @@ common_src = [
'http_chunk.c',
'http_vhostdb.c',
'http-header-glue.c',
- 'inet_ntop_cache.c',
'joblist.c',
'keyvalue.c',
'log.c',
@@ -558,6 +557,7 @@ common_src = [
'plugin.c',
'rand.c',
'safe_memclear.c',
+ 'sock_addr.c',
'splaytree.c',
'stat_cache.c',
'status_counter.c',
@@ -570,6 +570,7 @@ endif
main_src = [
'configfile.c',
'connections.c',
+ 'inet_ntop_cache.c',
'network_darwin_sendfile.c',
'network_freebsd_sendfile.c',
'network_linux_sendfile.c',
diff --git a/src/mod_evasive.c b/src/mod_evasive.c
index 26362c09..1e0fad44 100644
--- a/src/mod_evasive.c
+++ b/src/mod_evasive.c
@@ -4,6 +4,7 @@
#include "log.h"
#include "buffer.h"
#include "response.h"
+#include "sock_addr.h"
#include "plugin.h"
@@ -157,37 +158,15 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) {
/* no limit set, nothing to block */
if (p->conf.max_conns == 0) return HANDLER_GO_ON;
- switch (con->dst_addr.plain.sa_family) {
- case AF_INET:
-#ifdef HAVE_IPV6
- case AF_INET6:
-#endif
- break;
- default: /* Address family not supported */
- return HANDLER_GO_ON;
- };
-
for (j = 0; j < srv->conns->used; j++) {
connection *c = srv->conns->ptr[j];
/* check if other connections are already actively serving data for the same IP
* we can only ban connections which are already behind the 'read request' state
* */
- if (c->dst_addr.plain.sa_family != con->dst_addr.plain.sa_family) continue;
if (c->state <= CON_STATE_REQUEST_END) continue;
- switch (con->dst_addr.plain.sa_family) {
- case AF_INET:
- if (c->dst_addr.ipv4.sin_addr.s_addr != con->dst_addr.ipv4.sin_addr.s_addr) continue;
- break;
-#ifdef HAVE_IPV6
- case AF_INET6:
- if (0 != memcmp(c->dst_addr.ipv6.sin6_addr.s6_addr, con->dst_addr.ipv6.sin6_addr.s6_addr, 16)) continue;
- break;
-#endif
- default: /* Address family not supported, should never be reached */
- continue;
- };
+ if (!sock_addr_is_addr_eq(&c->dst_addr, &con->dst_addr)) continue;
conns_by_ip++;
if (conns_by_ip > p->conf.max_conns) {
diff --git a/src/mod_extforward.c b/src/mod_extforward.c
index 0364f31f..0d1d7d7b 100644
--- a/src/mod_extforward.c
+++ b/src/mod_extforward.c
@@ -4,7 +4,7 @@
#include "log.h"
#include "buffer.h"
#include "request.h"
-#include "inet_ntop_cache.h"
+#include "sock_addr.h"
#include "plugin.h"
@@ -1403,10 +1403,8 @@ static int mod_extforward_hap_PROXY_v2 (connection * const con,
switch (hdr->v2.fam) {
case 0x11: /* TCPv4 */
- memset(&con->dst_addr.ipv4, 0, sizeof(struct sockaddr_in));
- con->dst_addr.ipv4.sin_family = AF_INET;
- con->dst_addr.ipv4.sin_port = hdr->v2.addr.ip4.src_port;
- con->dst_addr.ipv4.sin_addr.s_addr = hdr->v2.addr.ip4.src_addr;
+ sock_addr_assign(&con->dst_addr, AF_INET, hdr->v2.addr.ip4.src_port,
+ &hdr->v2.addr.ip4.src_addr);
sock_addr_inet_ntop_copy_buffer(con->dst_addr_buf, &con->dst_addr);
#if 0
((struct sockaddr_in *)&by)->sin_family = AF_INET;
@@ -1419,10 +1417,8 @@ static int mod_extforward_hap_PROXY_v2 (connection * const con,
break;
#ifdef HAVE_IPV6
case 0x21: /* TCPv6 */
- memset(&con->dst_addr.ipv6, 0, sizeof(struct sockaddr_in6));
- con->dst_addr.ipv6.sin6_family = AF_INET6;
- con->dst_addr.ipv6.sin6_port = hdr->v2.addr.ip6.src_port;
- memcpy(&con->dst_addr.ipv6.sin6_addr, hdr->v2.addr.ip6.src_addr, 16);
+ sock_addr_assign(&con->dst_addr, AF_INET6, hdr->v2.addr.ip6.src_port,
+ &hdr->v2.addr.ip6.src_addr);
sock_addr_inet_ntop_copy_buffer(con->dst_addr_buf, &con->dst_addr);
#if 0
((struct sockaddr_in6 *)&by)->sin6_family = AF_INET6;
@@ -1441,9 +1437,7 @@ static int mod_extforward_hap_PROXY_v2 (connection * const con,
char *z = memchr(src_addr, '\0', UNIX_PATH_MAX);
if (NULL == z) return -1; /* invalid addr; too long */
len = (uint32_t)(z - src_addr + 1); /*(+1 for '\0')*/
- memset(&con->dst_addr.un, 0, sizeof(struct sockaddr_un));
- con->dst_addr.un.sun_family = AF_UNIX;
- memcpy(&con->dst_addr.un.sun_path, src_addr, len);
+ sock_addr_assign(&con->dst_addr, AF_UNIX, 0, src_addr);
buffer_copy_string_len(con->dst_addr_buf, src_addr, len);
}
#if 0 /*(dst_addr should be identical to src_addr for AF_UNIX)*/
diff --git a/src/mod_proxy.c b/src/mod_proxy.c
index a0a8dbc1..8ea72a05 100644
--- a/src/mod_proxy.c
+++ b/src/mod_proxy.c
@@ -7,10 +7,10 @@
#include "base.h"
#include "array.h"
#include "buffer.h"
-#include "inet_ntop_cache.h"
#include "keyvalue.h"
#include "log.h"
#include "plugin.h"
+#include "sock_addr.h"
#include "status_counter.h"
/**
@@ -572,6 +572,7 @@ static void proxy_set_Forwarded(connection *con, const unsigned int flags) {
}
if (flags & PROXY_FORWARDED_FOR) {
+ int family = sock_addr_get_family(&con->dst_addr);
buffer_append_string_len(ds->value, CONST_STR_LEN("for="));
if (NULL != dsfor) {
/* over-simplified test expecting only IPv4 or IPv6 addresses,
@@ -587,16 +588,14 @@ static void proxy_set_Forwarded(connection *con, const unsigned int flags) {
ds->value, CONST_BUF_LEN(dsfor->value));
if (ipv6) buffer_append_string_len(ds->value, CONST_STR_LEN("]"));
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
- } else if (con->dst_addr.plain.sa_family == AF_INET) {
+ } else if (family == AF_INET) {
/*(Note: if :port is added, then must be quoted-string:
* e.g. for="...:port")*/
buffer_append_string_buffer(ds->value, con->dst_addr_buf);
- #ifdef HAVE_IPV6
- } else if (con->dst_addr.plain.sa_family == AF_INET6) {
+ } else if (family == AF_INET6) {
buffer_append_string_len(ds->value, CONST_STR_LEN("\"["));
buffer_append_string_buffer(ds->value, con->dst_addr_buf);
buffer_append_string_len(ds->value, CONST_STR_LEN("]\""));
- #endif
} else {
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
buffer_append_string_backslash_escaped(
@@ -607,39 +606,30 @@ static void proxy_set_Forwarded(connection *con, const unsigned int flags) {
}
if (flags & PROXY_FORWARDED_BY) {
+ int family = sock_addr_get_family(&con->srv_socket->addr);
/* Note: getsockname() and inet_ntop() are expensive operations.
* (recommendation: do not to enable by=... unless required)
* future: might use con->srv_socket->srv_token if addr is not
* INADDR_ANY or in6addr_any, but must omit optional :port
* from con->srv_socket->srv_token for consistency */
- sock_addr *addr = &con->srv_socket->addr;
- sock_addr addrbuf;
- socklen_t addrlen = sizeof(addrbuf);
if (semicolon) buffer_append_string_len(ds->value, CONST_STR_LEN(";"));
buffer_append_string_len(ds->value, CONST_STR_LEN("by="));
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
- if (addr->plain.sa_family == AF_INET) {
- if (0==getsockname(con->fd,(struct sockaddr *)&addrbuf,&addrlen)) {
- sock_addr_inet_ntop_append_buffer(ds->value, &addrbuf);
- }
- buffer_append_string_len(ds->value, CONST_STR_LEN(":"));
- buffer_append_int(ds->value, ntohs(addr->ipv4.sin_port));
- #ifdef HAVE_IPV6
- } else if (addr->plain.sa_family == AF_INET6) {
- if (0 == getsockname(con->fd,(struct sockaddr *)&addrbuf,&addrlen)){
- buffer_append_string_len(ds->value, CONST_STR_LEN("["));
- sock_addr_inet_ntop_append_buffer(ds->value, &addrbuf);
- buffer_append_string_len(ds->value, CONST_STR_LEN("]"));
- buffer_append_string_len(ds->value, CONST_STR_LEN(":"));
- buffer_append_int(ds->value, ntohs(addr->ipv6.sin6_port));
- }
- #endif
#ifdef HAVE_SYS_UN_H
- } else if (addr->plain.sa_family == AF_UNIX) {
+ /* special-case: might need to encode unix domain socket path */
+ if (family == AF_UNIX) {
buffer_append_string_backslash_escaped(
ds->value, CONST_BUF_LEN(con->srv_socket->srv_token));
+ }
+ else
#endif
+ {
+ sock_addr addr;
+ socklen_t addrlen = sizeof(addr);
+ if (0 == getsockname(con->fd,(struct sockaddr *)&addr, &addrlen)) {
+ sock_addr_stringify_append_buffer(ds->value, &addr);
+ }
}
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
semicolon = 1;
diff --git a/src/network.c b/src/network.c
index 6b92ae07..51dce3cc 100644
--- a/src/network.c
+++ b/src/network.c
@@ -5,12 +5,10 @@
#include "log.h"
#include "connections.h"
#include "plugin.h"
-#include "joblist.h"
#include "configfile.h"
-#include "inet_ntop_cache.h"
+#include "sock_addr.h"
#include "network_backends.h"
-#include "sys-mmap.h"
#include "sys-socket.h"
#include <sys/types.h>
@@ -71,22 +69,7 @@ static handler_t network_server_handle_fdevent(server *srv, void *context, int r
static void network_host_normalize_addr_str(buffer *host, sock_addr *addr) {
buffer_reset(host);
- if (addr->plain.sa_family == AF_INET6)
- buffer_append_string_len(host, CONST_STR_LEN("["));
- sock_addr_inet_ntop_append_buffer(host, addr);
- if (addr->plain.sa_family == AF_INET6)
- buffer_append_string_len(host, CONST_STR_LEN("]"));
- if (addr->plain.sa_family != AF_UNIX) {
- #ifdef HAVE_IPV6
- unsigned short port = (addr->plain.sa_family == AF_INET)
- ? ntohs(addr->ipv4.sin_port)
- : ntohs(addr->ipv6.sin6_port);
- #else
- unsigned short port = ntohs(addr->ipv4.sin_port);
- #endif
- buffer_append_string_len(host, CONST_STR_LEN(":"));
- buffer_append_int(host, (int)port);
- }
+ sock_addr_stringify_append_buffer(host, addr);
}
static int network_host_parse_addr(server *srv, sock_addr *addr, socklen_t *addr_len, buffer *host, int use_ipv6) {
@@ -146,6 +129,7 @@ static int network_server_init(server *srv, buffer *host_token, size_t sidx, int
specific_config *s = srv->config_storage[sidx];
socklen_t addr_len = sizeof(sock_addr);
sock_addr addr;
+ int family = 0;
int set_v6only = 0;
#ifdef __WIN32
@@ -199,8 +183,10 @@ static int network_server_init(server *srv, buffer *host_token, size_t sidx, int
return -1;
}
+ family = sock_addr_get_family(&addr);
+
#ifdef HAVE_IPV6
- if (*host != '\0' && AF_INET6 == addr.plain.sa_family) {
+ if (*host != '\0' && AF_INET6 == family) {
if (s->set_v6only) {
set_v6only = 1;
} else {
@@ -256,10 +242,10 @@ static int network_server_init(server *srv, buffer *host_token, size_t sidx, int
}
} else
#ifdef HAVE_SYS_UN_H
- if (AF_UNIX == srv_socket->addr.plain.sa_family) {
+ if (AF_UNIX == family) {
/* check if the socket exists and try to connect to it. */
force_assert(host); /*(static analysis hint)*/
- if (-1 == (srv_socket->fd = fdevent_socket_cloexec(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
+ if (-1 == (srv_socket->fd = fdevent_socket_cloexec(AF_UNIX, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
return -1;
}
@@ -291,7 +277,7 @@ static int network_server_init(server *srv, buffer *host_token, size_t sidx, int
} else
#endif
{
- if (-1 == (srv_socket->fd = fdevent_socket_nb_cloexec(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
+ if (-1 == (srv_socket->fd = fdevent_socket_nb_cloexec(family, SOCK_STREAM, IPPROTO_TCP))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
return -1;
}
@@ -315,7 +301,7 @@ static int network_server_init(server *srv, buffer *host_token, size_t sidx, int
return -1;
}
- if (srv_socket->addr.plain.sa_family != AF_UNIX) {
+ if (family != AF_UNIX) {
if (fdevent_set_tcp_nodelay(srv_socket->fd, 1) < 0) {
log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(TCP_NODELAY) failed:", strerror(errno));
return -1;
@@ -330,7 +316,7 @@ static int network_server_init(server *srv, buffer *host_token, size_t sidx, int
}
if (-1 != stdin_fd) { } else
- if (srv_socket->addr.plain.sa_family == AF_UNIX && !buffer_string_is_empty(s->socket_perms)) {
+ if (AF_UNIX == family && !buffer_string_is_empty(s->socket_perms)) {
mode_t m = 0;
for (char *str = s->socket_perms->ptr; *str; ++str) {
m <<= 3;
diff --git a/src/request.c b/src/request.c
index fbfed15a..50156081 100644
--- a/src/request.c
+++ b/src/request.c
@@ -3,7 +3,7 @@
#include "request.h"
#include "keyvalue.h"
#include "log.h"
-#include "inet_ntop_cache.h"
+#include "sock_addr.h"
#include <sys/stat.h>
diff --git a/src/server.c b/src/server.c
index de4b0a3a..4cd8699c 100644
--- a/src/server.c
+++ b/src/server.c
@@ -14,6 +14,7 @@
#include "http_vhostdb.h"
#include "fdevent.h"
#include "connections.h"
+#include "sock_addr.h"
#include "stat_cache.h"
#include "plugin.h"
#include "joblist.h"
@@ -428,36 +429,12 @@ static server_socket * server_oneshot_getsock(server *srv, sock_addr *cnt_addr)
size_t i;
for (i = 0; i < srv->srv_sockets.used; ++i) {
srv_socket = srv->srv_sockets.ptr[i];
- if (cnt_addr->plain.sa_family != srv_socket->addr.plain.sa_family) continue;
- switch (cnt_addr->plain.sa_family) {
- case AF_INET:
- if (srv_socket->addr.ipv4.sin_port != cnt_addr->ipv4.sin_port) continue;
- if (srv_socket->addr.ipv4.sin_addr.s_addr == cnt_addr->ipv4.sin_addr.s_addr) {
- return srv_socket;
- }
- if (srv_socket->addr.ipv4.sin_addr.s_addr == htonl(INADDR_ANY)) {
- srv_socket_wild = srv_socket;
- }
- continue;
- #ifdef HAVE_IPV6
- case AF_INET6:
- if (srv_socket->addr.ipv6.sin6_port != cnt_addr->ipv6.sin6_port) continue;
- if (0 == memcmp(&srv_socket->addr.ipv6.sin6_addr, &cnt_addr->ipv6.sin6_addr, sizeof(struct in6_addr))) {
- return srv_socket;
- }
- if (0 == memcmp(&srv_socket->addr.ipv6.sin6_addr, &in6addr_any, sizeof(struct in6_addr))) {
- srv_socket_wild = srv_socket;
- }
- continue;
- #endif
- #ifdef HAVE_SYS_UN_H
- case AF_UNIX:
- if (0 == strcmp(srv_socket->addr.un.sun_path, cnt_addr->un.sun_path)) {
- return srv_socket;
- }
- continue;
- #endif
- default: continue;
+ if (!sock_addr_is_port_eq(&srv_socket->addr,cnt_addr)) continue;
+ if (sock_addr_is_addr_eq(&srv_socket->addr,cnt_addr)) return srv_socket;
+
+ if (NULL != srv_socket_wild) continue;
+ if (sock_addr_is_addr_wildcard(&srv_socket->addr)) {
+ srv_socket_wild = srv_socket;
}
}
@@ -524,7 +501,7 @@ static int server_oneshot_init(server *srv, int fd) {
return 0;
}
- if (cnt_addr.plain.sa_family != AF_UNIX) {
+ if (sock_addr_get_family(&cnt_addr) != AF_UNIX) {
network_accept_tcp_nagle_disable(fd);
}
diff --git a/src/sock_addr.c b/src/sock_addr.c
new file mode 100644
index 00000000..41fb92a0
--- /dev/null
+++ b/src/sock_addr.c
@@ -0,0 +1,685 @@
+#include "first.h"
+
+#include "sock_addr.h"
+
+#include "sys-socket.h"
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+#ifndef _WIN32
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+
+#include "base.h"
+#include "log.h"
+
+
+unsigned short sock_addr_get_port (const sock_addr *saddr)
+{
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ return ntohs(saddr->ipv4.sin_port);
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return ntohs(saddr->ipv6.sin6_port);
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ /*case AF_UNIX:*/
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_is_addr_wildcard (const sock_addr *saddr)
+{
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ return (saddr->ipv4.sin_addr.s_addr == INADDR_ANY); /*(htonl(0x0))*/
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return !memcmp(&saddr->ipv6.sin6_addr,&in6addr_any,sizeof(in6addr_any));
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ /*case AF_UNIX:*/
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_is_family_eq (const sock_addr *saddr1, const sock_addr *saddr2)
+{
+ return saddr1->plain.sa_family == saddr2->plain.sa_family;
+}
+
+
+int sock_addr_is_port_eq (const sock_addr *saddr1, const sock_addr *saddr2)
+{
+ if (!sock_addr_is_family_eq(saddr1, saddr2)) return 0;
+ switch (saddr1->plain.sa_family) {
+ case AF_INET:
+ return saddr1->ipv4.sin_port == saddr2->ipv4.sin_port;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return saddr1->ipv6.sin6_port == saddr2->ipv6.sin6_port;
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ return 1;
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_is_addr_eq (const sock_addr *saddr1, const sock_addr *saddr2)
+{
+ if (!sock_addr_is_family_eq(saddr1, saddr2)) return 0;
+ switch (saddr1->plain.sa_family) {
+ case AF_INET:
+ return saddr1->ipv4.sin_addr.s_addr == saddr2->ipv4.sin_addr.s_addr;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return 0 == memcmp(&saddr1->ipv6.sin6_addr, &saddr2->ipv6.sin6_addr,
+ sizeof(struct in6_addr));
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ return 0 == strcmp(saddr1->un.sun_path, saddr2->un.sun_path);
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+#if 0
+int sock_addr_is_addr_port_eq (const sock_addr *saddr1, const sock_addr *saddr2)
+{
+ if (!sock_addr_is_family_eq(saddr1, saddr2)) return 0;
+ switch (saddr1->plain.sa_family) {
+ case AF_INET:
+ return saddr1->ipv4.sin_port == saddr2->ipv4.sin_port
+ && saddr1->ipv4.sin_addr.s_addr == saddr2->ipv4.sin_addr.s_addr;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return saddr1->ipv6.sin6_port == saddr2->ipv6.sin6_port
+ && 0 == memcmp(&saddr1->ipv6.sin6_addr, &saddr2->ipv6.sin6_addr,
+ sizeof(struct in6_addr));
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ return 0 == strcmp(saddr1->un.sun_path, saddr2->un.sun_path);
+ #endif
+ default:
+ return 0;
+ }
+}
+#endif
+
+
+int sock_addr_is_addr_eq_bits(const sock_addr *a, const sock_addr *b, int bits) {
+ switch (a->plain.sa_family) {
+ case AF_INET:
+ {
+ uint32_t nm; /* build netmask */
+ if (bits > 32) bits = 32;
+ nm = htonl(~((1u << (32 - (0 != bits ? bits : 32))) - 1));
+ if (b->plain.sa_family == AF_INET) {
+ return
+ (a->ipv4.sin_addr.s_addr & nm) == (b->ipv4.sin_addr.s_addr & nm);
+ }
+ #ifdef HAVE_IPV6
+ else if (b->plain.sa_family == AF_INET6
+ && IN6_IS_ADDR_V4MAPPED(&b->ipv6.sin6_addr)) {
+ #ifdef s6_addr32
+ in_addr_t x = b->ipv6.sin6_addr.s6_addr32[3];
+ #else
+ in_addr_t x;
+ memcpy(&x, b->ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
+ #endif
+ return ((a->ipv4.sin_addr.s_addr & nm) == (x & nm));
+ }
+ #endif
+ return 0;
+ }
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ if (bits > 128) bits = 128;
+ if (b->plain.sa_family == AF_INET6) {
+ uint8_t *c = (uint8_t *)&a->ipv6.sin6_addr.s6_addr[0];
+ uint8_t *d = (uint8_t *)&b->ipv6.sin6_addr.s6_addr[0];
+ int match;
+ do {
+ match = (bits >= 8)
+ ? *c++ == *d++
+ : (*c >> (8 - bits)) == (*d >> (8 - bits));
+ } while (match && (bits -= 8) > 0);
+ return match;
+ }
+ else if (b->plain.sa_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED(&a->ipv6.sin6_addr)) {
+ uint32_t nm = bits < 128
+ ? htonl(~(~0u >> (bits > 96 ? bits - 96 : 0)))
+ : ~0u;
+ #ifdef s6_addr32
+ in_addr_t x = a->ipv6.sin6_addr.s6_addr32[3];
+ #else
+ in_addr_t x;
+ memcpy(&x, a->ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
+ #endif
+ return ((x & nm) == (b->ipv4.sin_addr.s_addr & nm));
+ }
+ return 0;
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ /*case AF_UNIX:*/
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_assign (sock_addr *saddr, int family, unsigned short nport, const void *naddr)
+{
+ switch (family) {
+ case AF_INET:
+ memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_port = nport;
+ memcpy(&saddr->ipv4.sin_addr, naddr, 4);
+ return 0;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ memset(&saddr->ipv6, 0, sizeof(struct sockaddr_in6));
+ saddr->ipv6.sin6_family = AF_INET6;
+ saddr->ipv6.sin6_port = nport;
+ memcpy(&saddr->ipv6.sin6_addr, naddr, 16);
+ return 0;
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ {
+ size_t len = strlen((char *)naddr) + 1;
+ if (len > sizeof(saddr->un.sun_path)) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ memset(&saddr->un, 0, sizeof(struct sockaddr_un));
+ saddr->un.sun_family = AF_UNIX;
+ memcpy(saddr->un.sun_path, naddr, len);
+ return 0;
+ }
+ #endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+}
+
+
+int sock_addr_inet_pton(sock_addr *saddr, const char *str,
+ int family, unsigned short port)
+{
+ switch (family) {
+ case AF_INET:
+ memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_port = htons(port);
+ #if defined(HAVE_INET_ATON) /*(Windows does not provide inet_aton())*/
+ return (0 != inet_aton(str, &saddr->ipv4.sin_addr));
+ #else
+ return ((saddr->ipv4.sin_addr.s_addr = inet_addr(str)) != INADDR_NONE);
+ #endif
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ memset(&saddr->ipv6, 0, sizeof(struct sockaddr_in6));
+ saddr->ipv6.sin6_family = AF_INET6;
+ saddr->ipv6.sin6_port = htons(port);
+ return inet_pton(AF_INET6, str, &saddr->ipv6.sin6_addr);
+ #endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+}
+
+
+const char * sock_addr_inet_ntop(const sock_addr *saddr, char *buf, socklen_t sz)
+{
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ #if defined(HAVE_INET_PTON) /*(expect inet_ntop if inet_pton)*/
+ return inet_ntop(AF_INET,(const void *)&saddr->ipv4.sin_addr,buf,sz);
+ #else /*(inet_ntoa() not thread-safe)*/
+ return inet_ntoa(saddr->ipv4.sin_addr);
+ #endif
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return inet_ntop(AF_INET6,(const void *)&saddr->ipv6.sin6_addr,buf,sz);
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ return saddr->un.sun_path;
+ #endif
+ default:
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+}
+
+
+int sock_addr_inet_ntop_copy_buffer(buffer *b, const sock_addr *saddr)
+{
+ /*(incur cost of extra copy to avoid potential extra memory allocation)*/
+ char buf[UNIX_PATH_MAX];
+ const char *s = sock_addr_inet_ntop(saddr, buf, sizeof(buf));
+ if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
+ buffer_copy_string(b, s);
+ return 0;
+}
+
+
+int sock_addr_inet_ntop_append_buffer(buffer *b, const sock_addr *saddr)
+{
+ /*(incur cost of extra copy to avoid potential extra memory allocation)*/
+ char buf[UNIX_PATH_MAX];
+ const char *s = sock_addr_inet_ntop(saddr, buf, sizeof(buf));
+ if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
+ buffer_append_string(b, s);
+ return 0;
+}
+
+int sock_addr_stringify_append_buffer(buffer *b, const sock_addr *saddr)
+{
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ if (0 != sock_addr_inet_ntop_append_buffer(b, saddr)) return -1;
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+ buffer_append_int(b, ntohs(saddr->ipv4.sin_port));
+ return 0;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ buffer_append_string_len(b, CONST_STR_LEN("["));
+ if (0 != sock_addr_inet_ntop_append_buffer(b, saddr)) {
+ buffer_string_set_length(b, buffer_string_length(b)-1);
+ return -1;
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("]"));
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+ buffer_append_int(b, ntohs(saddr->ipv6.sin6_port));
+ return 0;
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ buffer_append_string(b, saddr->un.sun_path);
+ return 0;
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_nameinfo_append_buffer(server *srv, buffer *b, const sock_addr *saddr)
+{
+ /*(this routine originates from
+ * http-header-glue.c:http_response_redirect_to_directory())*/
+ /*(note: name resolution here is *blocking*)*/
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ {
+ struct hostent *he = gethostbyaddr((char *)&saddr->ipv4.sin_addr,
+ sizeof(struct in_addr), AF_INET);
+ if (NULL == he) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "SdS", "NOTICE: gethostbyaddr failed: ",
+ h_errno, ", using ip-address instead");
+
+ sock_addr_inet_ntop_append_buffer(b, saddr);
+ } else {
+ buffer_append_string(b, he->h_name);
+ }
+ return 0;
+ }
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ char hbuf[256];
+ if (0 != getnameinfo((const struct sockaddr *)(&saddr->ipv6),
+ sizeof(saddr->ipv6),
+ hbuf, sizeof(hbuf), NULL, 0, 0)) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "SSS", "NOTICE: getnameinfo failed: ",
+ strerror(errno), ", using ip-address instead");
+
+ buffer_append_string_len(b, CONST_STR_LEN("["));
+ sock_addr_inet_ntop_append_buffer(b, saddr);
+ buffer_append_string_len(b, CONST_STR_LEN("]"));
+ } else {
+ buffer_append_string(b, hbuf);
+ }
+ return 0;
+ }
+ #endif
+ default:
+ log_error_write(srv, __FILE__, __LINE__,
+ "S", "ERROR: unsupported address-type");
+ return -1;
+ }
+}
+
+
+int sock_addr_from_str_hints(server *srv, sock_addr *saddr, socklen_t *len, const char *str, int family, unsigned short port)
+{
+ /*(note: name resolution here is *blocking*)*/
+ switch(family) {
+ case AF_UNSPEC:
+ if (0 == strcmp(str, "localhost")) {
+ /*(special-case "localhost" to IPv4 127.0.0.1)*/
+ memset(saddr, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ return 1;
+ }
+ #ifdef HAVE_IPV6
+ else {
+ struct addrinfo hints, *res;
+ int r;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ 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(saddr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ if (AF_INET6 == saddr->plain.sa_family) {
+ saddr->ipv6.sin6_port = htons(port);
+ *len = sizeof(struct sockaddr_in6);
+ }
+ else { /* AF_INET */
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ }
+ return 1;
+ }
+ #else
+ /* fall through */
+ #endif
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ memset(saddr, 0, sizeof(struct sockaddr_in6));
+ saddr->ipv6.sin6_family = AF_INET6;
+ if (0 == strcmp(str, "::")) {
+ saddr->ipv6.sin6_addr = in6addr_any;
+ }
+ else if (0 == strcmp(str, "::1")) {
+ saddr->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(saddr, res->ai_addr, res->ai_addrlen);
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->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(saddr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ }
+ saddr->ipv6.sin6_port = htons(port);
+ *len = sizeof(struct sockaddr_in6);
+ return 1;
+ #endif
+ case AF_INET:
+ memset(saddr, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ if (0 == strcmp(str, "0.0.0.0")) {
+ saddr->ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ else if (0 == strcmp(str, "127.0.0.1")) {
+ saddr->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(saddr, 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(&saddr->ipv4.sin_addr.s_addr,
+ he->h_addr_list[0], he->h_length);
+ #endif
+ }
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ return 1;
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ memset(saddr, 0, sizeof(struct sockaddr_un));
+ saddr->un.sun_family = AF_UNIX;
+ {
+ size_t hostlen = strlen(str) + 1;
+ if (hostlen > sizeof(saddr->un.sun_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sS",
+ "unix socket filename too long:", str);
+ /*errno = ENAMETOOLONG;*/
+ return 0;
+ }
+ memcpy(saddr->un.sun_path, str, hostlen);
+ #if defined(SUN_LEN)
+ *len = SUN_LEN(&saddr->un);
+ #else
+ /* stevens says: */
+ *len = hostlen + sizeof(saddr->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;
+ }
+}
+
+
+int sock_addr_from_str_numeric(server *srv, sock_addr *saddr, const char *str)
+{
+ /*(note: does not handle port if getaddrinfo() is not available)*/
+ /*(note: getaddrinfo() is stricter than inet_aton() in what is accepted)*/
+ /*(this routine originates from mod_extforward.c:ipstr_to_sockaddr()*/
+ #ifdef HAVE_IPV6
+ struct addrinfo hints, *addrlist = NULL;
+ int result;
+
+ /**
+ * quoting $ man getaddrinfo
+ *
+ * NOTES
+ * AI_ADDRCONFIG, AI_ALL, and AI_V4MAPPED are available since glibc 2.3.3.
+ * AI_NUMERICSERV is available since glibc 2.3.4.
+ */
+ #ifndef AI_NUMERICSERV
+ #define AI_NUMERICSERV 0
+ #endif
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+
+ errno = 0;
+ result = getaddrinfo(str, NULL, &hints, &addrlist);
+
+ if (result != 0) {
+ log_error_write(srv, __FILE__, __LINE__, "SSSs(S)",
+ "could not parse ip address ", str, " because ",
+ gai_strerror(result), strerror(errno));
+ } else if (addrlist == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "Problem in parsing ip address ", str,
+ ": succeeded, but no information returned");
+ result = -1;
+ } else switch (addrlist->ai_family) {
+ case AF_INET:
+ memcpy(&saddr->ipv4, addrlist->ai_addr, sizeof(saddr->ipv4));
+ force_assert(AF_INET == saddr->plain.sa_family);
+ break;
+ case AF_INET6:
+ memcpy(&saddr->ipv6, addrlist->ai_addr, sizeof(saddr->ipv6));
+ force_assert(AF_INET6 == saddr->plain.sa_family);
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "Problem in parsing ip address ", str,
+ ": succeeded, but unknown family");
+ result = -1;
+ break;
+ }
+
+ freeaddrinfo(addrlist);
+ return (0 == result);
+ #else
+ UNUSED(srv);
+ saddr->ipv4.sin_addr.s_addr = inet_addr(str);
+ saddr->plain.sa_family = AF_INET;
+ return (saddr->ipv4.sin_addr.s_addr != 0xFFFFFFFF);
+ #endif
+}
+
+
+int sock_addr_from_buffer_hints_numeric(server *srv, sock_addr *saddr, socklen_t *len, const buffer *b, int family, unsigned short port)
+{
+ /*(this routine originates from mod_fastcgi.c and mod_scgi.c)*/
+ if (buffer_string_is_empty(b)) {
+ /*(preserve existing behavior (for now))*/
+ /*(would be better if initialized default when reading config)*/
+ memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ return 1;
+ }
+ else if (1 == sock_addr_inet_pton(saddr, b->ptr, family, port)) {
+ *len = (family == AF_INET)
+ ? sizeof(struct sockaddr_in) /* family == AF_INET */
+ : sizeof(struct sockaddr_in6); /* family == AF_INET6 */
+ return 1;
+ }
+ #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
+ else if (family == AF_INET6) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid IPv6 address literal:", b);
+ return 0;
+ }
+ #endif
+ #ifndef HAVE_INET_PTON /*(preserve existing behavior (for now))*/
+ else {
+ struct hostent *he = gethostbyname(b->ptr);
+ if (NULL == he) {
+ log_error_write(srv, __FILE__, __LINE__, "sdb",
+ "gethostbyname failed:", h_errno, b);
+ 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;
+ }
+
+ memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
+ memcpy(&saddr->ipv4.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ }
+ #else
+ UNUSED(srv);
+ #endif
+
+ return 0;
+}
diff --git a/src/sock_addr.h b/src/sock_addr.h
new file mode 100644
index 00000000..e949e7ef
--- /dev/null
+++ b/src/sock_addr.h
@@ -0,0 +1,51 @@
+#ifndef INCLUDED_SOCK_ADDR_H
+#define INCLUDED_SOCK_ADDR_H
+#include "first.h"
+
+#include <sys/types.h>
+#include "sys-socket.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+
+
+union sock_addr {
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 ipv6;
+#endif
+ struct sockaddr_in ipv4;
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un un;
+#endif
+ struct sockaddr plain;
+};
+
+
+static inline int sock_addr_get_family (const sock_addr *saddr);
+static inline int sock_addr_get_family (const sock_addr *saddr) {
+ return saddr->plain.sa_family;
+}
+
+unsigned short sock_addr_get_port (const sock_addr *saddr);
+int sock_addr_is_addr_wildcard (const sock_addr *saddr);
+int sock_addr_is_family_eq (const sock_addr *saddr1, const sock_addr *saddr2);
+int sock_addr_is_port_eq (const sock_addr *saddr1, const sock_addr *saddr2);
+int sock_addr_is_addr_eq (const sock_addr *saddr1, const sock_addr *saddr2);
+/*int sock_addr_is_addr_port_eq (const sock_addr *saddr1, const sock_addr *saddr2);*/
+int sock_addr_is_addr_eq_bits(const sock_addr *a, const sock_addr *b, int bits);
+int sock_addr_assign (sock_addr *saddr, int family, unsigned short nport, const void *naddr);
+
+int sock_addr_inet_pton(sock_addr *saddr, const char *str, int family, unsigned short port);
+
+const char * sock_addr_inet_ntop(const sock_addr *saddr, char *buf, socklen_t sz);
+int sock_addr_inet_ntop_copy_buffer(buffer *b, const sock_addr *saddr);
+int sock_addr_inet_ntop_append_buffer(buffer *b, const sock_addr *saddr);
+int sock_addr_stringify_append_buffer(buffer *b, const sock_addr *saddr);
+int sock_addr_nameinfo_append_buffer(server *srv, buffer *b, const sock_addr *saddr);
+
+int sock_addr_from_buffer_hints_numeric(server *srv, sock_addr *saddr, socklen_t *len, const buffer *b, int family, unsigned short port);
+int sock_addr_from_str_hints(server *srv, sock_addr *saddr, socklen_t *len, const char *str, int family, unsigned short port);
+int sock_addr_from_str_numeric(server *srv, sock_addr *saddr, const char *str);
+
+
+#endif
diff --git a/src/sys-socket.h b/src/sys-socket.h
index 93a47404..25b7eb0f 100644
--- a/src/sys-socket.h
+++ b/src/sys-socket.h
@@ -16,8 +16,9 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
-#include <arpa/inet.h>
+#endif
#endif
diff --git a/src/test_configfile.c b/src/test_configfile.c
index 75cd66e4..3618be40 100644
--- a/src/test_configfile.c
+++ b/src/test_configfile.c
@@ -47,22 +47,7 @@ static void test_configfile_addrbuf_eq_remote_ip_mask (void) {
sock_addr rmt;
for (i = 0; i < (int)(sizeof(rmtmask)/sizeof(rmtmask[0])); ++i) {
- #ifndef HAVE_INET_PTON
- rmt.ipv4.sin_family = AF_INET;
- rmt.ipv4.sin_addr.s_addr = inet_addr(rmtmask[i].rmtstr);
- #else
- if (rmtmask[i].rmtfamily == AF_INET) {
- rmt.ipv4.sin_family = AF_INET;
- inet_pton(AF_INET, rmtmask[i].rmtstr, &rmt.ipv4.sin_addr);
- #ifdef HAVE_IPV6
- } else if (rmtmask[i].rmtfamily == AF_INET6) {
- rmt.ipv6.sin6_family = AF_INET6;
- inet_pton(AF_INET6, rmtmask[i].rmtstr, &rmt.ipv6.sin6_addr);
- #endif
- } else {
- continue;
- }
- #endif
+ sock_addr_inet_pton(&rmt, rmtmask[i].rmtstr, rmtmask[i].rmtfamily, 0);
buffer_copy_string(s, rmtmask[i].string);
slash = strchr(s->ptr,'/'); assert(slash);
m = config_addrbuf_eq_remote_ip_mask(NULL, s, slash, &rmt);