summaryrefslogtreecommitdiff
path: root/usr.sbin/unbound/util/netevent.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/unbound/util/netevent.c')
-rw-r--r--usr.sbin/unbound/util/netevent.c126
1 files changed, 98 insertions, 28 deletions
diff --git a/usr.sbin/unbound/util/netevent.c b/usr.sbin/unbound/util/netevent.c
index a2c0e6073e3..11c642a2bc3 100644
--- a/usr.sbin/unbound/util/netevent.c
+++ b/usr.sbin/unbound/util/netevent.c
@@ -51,6 +51,16 @@
#include "dnstap/dnstap.h"
#include "dnscrypt/dnscrypt.h"
#include "services/listen_dnsport.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
#ifdef HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
#endif
@@ -152,7 +162,7 @@ struct internal_signal {
static struct comm_point* comm_point_create_tcp_handler(
struct comm_base *base, struct comm_point* parent, size_t bufsize,
struct sldns_buffer* spoolbuf, comm_point_callback_type* callback,
- void* callback_arg);
+ void* callback_arg, struct unbound_socket* socket);
/* -------- End of local definitions -------- */
@@ -289,6 +299,7 @@ udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
# ifdef ENETDOWN
case ENETDOWN:
# endif
+ case EPERM:
if(verbosity < VERB_ALGO)
return 0;
default:
@@ -302,7 +313,7 @@ udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
/* 'Cannot assign requested address' also when disconnected */
|| (errno == EADDRNOTAVAIL)
# endif
- ) && verbosity < VERB_DETAIL)
+ ) && verbosity < VERB_ALGO)
return 0;
# ifdef EADDRINUSE
/* If SO_REUSEADDR is set, we could try to connect to the same server
@@ -408,7 +419,9 @@ static void p_ancil(const char* str, struct comm_reply* r)
log_info("%s: unknown srctype %d", str, r->srctype);
return;
}
+
if(r->srctype == 6) {
+#ifdef IPV6_PKTINFO
char buf[1024];
if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr,
buf, (socklen_t)sizeof(buf)) == 0) {
@@ -416,6 +429,7 @@ static void p_ancil(const char* str, struct comm_reply* r)
}
buf[sizeof(buf)-1]=0;
log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex);
+#endif
} else if(r->srctype == 4) {
#ifdef IP_PKTINFO
char buf1[1024], buf2[1024];
@@ -1200,7 +1214,7 @@ ssl_handshake(struct comm_point* c)
int r;
if(c->ssl_shake_state == comm_ssl_shake_hs_read) {
/* read condition satisfied back to writing */
- comm_point_listen_for_rw(c, 1, 1);
+ comm_point_listen_for_rw(c, 0, 1);
c->ssl_shake_state = comm_ssl_shake_none;
return 1;
}
@@ -1257,7 +1271,11 @@ ssl_handshake(struct comm_point* c)
if((SSL_get_verify_mode(c->ssl)&SSL_VERIFY_PEER)) {
/* verification */
if(SSL_get_verify_result(c->ssl) == X509_V_OK) {
+#ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
+ X509* x = SSL_get1_peer_certificate(c->ssl);
+#else
X509* x = SSL_get_peer_certificate(c->ssl);
+#endif
if(!x) {
log_addr(VERB_ALGO, "SSL connection failed: "
"no certificate",
@@ -1283,7 +1301,11 @@ ssl_handshake(struct comm_point* c)
#endif
X509_free(x);
} else {
+#ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
+ X509* x = SSL_get1_peer_certificate(c->ssl);
+#else
X509* x = SSL_get_peer_certificate(c->ssl);
+#endif
if(x) {
log_cert(VERB_ALGO, "peer certificate", x);
X509_free(x);
@@ -1300,6 +1322,7 @@ ssl_handshake(struct comm_point* c)
c->repinfo.addrlen);
}
+#ifdef HAVE_SSL_GET0_ALPN_SELECTED
/* check if http2 use is negotiated */
if(c->type == comm_http && c->h2_session) {
const unsigned char *alpn;
@@ -1311,13 +1334,14 @@ ssl_handshake(struct comm_point* c)
c->use_h2 = 1;
}
}
+#endif
/* setup listen rw correctly */
if(c->tcp_is_reading) {
if(c->ssl_shake_state != comm_ssl_shake_read)
comm_point_listen_for_rw(c, 1, 0);
} else {
- comm_point_listen_for_rw(c, 1, 1);
+ comm_point_listen_for_rw(c, 0, 1);
}
c->ssl_shake_state = comm_ssl_shake_none;
return 1;
@@ -1348,7 +1372,9 @@ ssl_handle_read(struct comm_point* c)
return tcp_req_info_handle_read_close(c->tcp_req_info);
return 0; /* shutdown, closed */
} else if(want == SSL_ERROR_WANT_READ) {
+#ifdef USE_WINSOCK
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
+#endif
return 1; /* read more later */
} else if(want == SSL_ERROR_WANT_WRITE) {
c->ssl_shake_state = comm_ssl_shake_hs_write;
@@ -1396,7 +1422,9 @@ ssl_handle_read(struct comm_point* c)
return tcp_req_info_handle_read_close(c->tcp_req_info);
return 0; /* shutdown, closed */
} else if(want == SSL_ERROR_WANT_READ) {
+#ifdef USE_WINSOCK
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
+#endif
return 1; /* read more later */
} else if(want == SSL_ERROR_WANT_WRITE) {
c->ssl_shake_state = comm_ssl_shake_hs_write;
@@ -1489,7 +1517,9 @@ ssl_handle_write(struct comm_point* c)
comm_point_listen_for_rw(c, 1, 0);
return 1; /* wait for read condition */
} else if(want == SSL_ERROR_WANT_WRITE) {
+#ifdef USE_WINSOCK
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
+#endif
return 1; /* write more later */
} else if(want == SSL_ERROR_SYSCALL) {
#ifdef EPIPE
@@ -1539,7 +1569,9 @@ ssl_handle_write(struct comm_point* c)
comm_point_listen_for_rw(c, 1, 0);
return 1; /* wait for read condition */
} else if(want == SSL_ERROR_WANT_WRITE) {
+#ifdef USE_WINSOCK
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
+#endif
return 1; /* write more later */
} else if(want == SSL_ERROR_SYSCALL) {
#ifdef EPIPE
@@ -1620,6 +1652,10 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
if(errno == ECONNRESET && verbosity < 2)
return 0; /* silence reset by peer */
#endif
+#ifdef ECONNREFUSED
+ if(errno == ECONNREFUSED && verbosity < 2)
+ return 0; /* silence reset by peer */
+#endif
#ifdef ENETUNREACH
if(errno == ENETUNREACH && verbosity < 2)
return 0; /* silence it */
@@ -1648,6 +1684,16 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
}
#endif
#else /* USE_WINSOCK */
+ if(WSAGetLastError() == WSAECONNREFUSED && verbosity < 2)
+ return 0;
+ if(WSAGetLastError() == WSAEHOSTDOWN && verbosity < 2)
+ return 0;
+ if(WSAGetLastError() == WSAEHOSTUNREACH && verbosity < 2)
+ return 0;
+ if(WSAGetLastError() == WSAENETDOWN && verbosity < 2)
+ return 0;
+ if(WSAGetLastError() == WSAENETUNREACH && verbosity < 2)
+ return 0;
if(WSAGetLastError() == WSAECONNRESET)
return 0;
if(WSAGetLastError() == WSAEINPROGRESS)
@@ -1681,7 +1727,8 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
(int)sldns_buffer_limit(c->buffer));
}
- log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ if(sldns_buffer_remaining(c->buffer) == 0)
+ log_err("in comm_point_tcp_handle_read buffer_remaining is not > 0 as expected, continuing with (harmless) 0 length recv");
r = recv(fd, (void*)sldns_buffer_current(c->buffer),
sldns_buffer_remaining(c->buffer), 0);
if(r == 0) {
@@ -2197,6 +2244,8 @@ ssl_http_read_more(struct comm_point* c)
log_crypto_err("could not SSL_read");
return 0;
}
+ verbose(VERB_ALGO, "ssl http read more skip to %d + %d",
+ (int)sldns_buffer_position(c->buffer), (int)r);
sldns_buffer_skip(c->buffer, (ssize_t)r);
return 1;
#else
@@ -2233,6 +2282,8 @@ http_read_more(int fd, struct comm_point* c)
&c->repinfo.addr, c->repinfo.addrlen);
return 0;
}
+ verbose(VERB_ALGO, "http read more skip to %d + %d",
+ (int)sldns_buffer_position(c->buffer), (int)r);
sldns_buffer_skip(c->buffer, r);
return 1;
}
@@ -2370,7 +2421,7 @@ http_process_chunk_header(struct comm_point* c)
return 1;
}
-/** handle nonchunked data segment */
+/** handle nonchunked data segment, 0=fail, 1=wait */
static int
http_nonchunk_segment(struct comm_point* c)
{
@@ -2379,7 +2430,7 @@ http_nonchunk_segment(struct comm_point* c)
* we are looking to read tcp_byte_count more data
* and then the transfer is done. */
size_t remainbufferlen;
- size_t got_now = sldns_buffer_limit(c->buffer) - c->http_stored;
+ size_t got_now = sldns_buffer_limit(c->buffer);
if(c->tcp_byte_count <= got_now) {
/* done, this is the last data fragment */
c->http_stored = 0;
@@ -2388,13 +2439,12 @@ http_nonchunk_segment(struct comm_point* c)
(void)(*c->callback)(c, c->cb_arg, NETEVENT_DONE, NULL);
return 1;
}
- c->tcp_byte_count -= got_now;
/* if we have the buffer space,
* read more data collected into the buffer */
remainbufferlen = sldns_buffer_capacity(c->buffer) -
sldns_buffer_limit(c->buffer);
- if(remainbufferlen >= c->tcp_byte_count ||
- remainbufferlen >= 2048) {
+ if(remainbufferlen+got_now >= c->tcp_byte_count ||
+ remainbufferlen >= (c->ssl?16384:2048)) {
size_t total = sldns_buffer_limit(c->buffer);
sldns_buffer_clear(c->buffer);
sldns_buffer_set_position(c->buffer, total);
@@ -2404,6 +2454,7 @@ http_nonchunk_segment(struct comm_point* c)
}
/* call callback with this data amount, then
* wait for more */
+ c->tcp_byte_count -= got_now;
c->http_stored = 0;
sldns_buffer_set_position(c->buffer, 0);
fptr_ok(fptr_whitelist_comm_point(c->callback));
@@ -2762,6 +2813,11 @@ comm_point_http_handle_read(int fd, struct comm_point* c)
return 0;
}
+ if(c->http_stored >= sldns_buffer_position(c->buffer)) {
+ /* read did not work but we wanted more data, there is
+ * no bytes to process now. */
+ return 1;
+ }
sldns_buffer_flip(c->buffer);
/* if we are partway in a segment of data, position us at the point
* where we left off previously */
@@ -3184,7 +3240,7 @@ void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
struct comm_point*
comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
- comm_point_callback_type* callback, void* callback_arg)
+ comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket)
{
struct comm_point* c = (struct comm_point*)calloc(1,
sizeof(struct comm_point));
@@ -3223,6 +3279,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
c->inuse = 0;
c->callback = callback;
c->cb_arg = callback_arg;
+ c->socket = socket;
evbits = UB_EV_READ | UB_EV_PERSIST;
/* ub_event stuff */
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
@@ -3244,7 +3301,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
struct comm_point*
comm_point_create_udp_ancil(struct comm_base *base, int fd,
sldns_buffer* buffer,
- comm_point_callback_type* callback, void* callback_arg)
+ comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket)
{
struct comm_point* c = (struct comm_point*)calloc(1,
sizeof(struct comm_point));
@@ -3283,6 +3340,7 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd,
#endif
c->callback = callback;
c->cb_arg = callback_arg;
+ c->socket = socket;
evbits = UB_EV_READ | UB_EV_PERSIST;
/* ub_event stuff */
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
@@ -3305,7 +3363,7 @@ static struct comm_point*
comm_point_create_tcp_handler(struct comm_base *base,
struct comm_point* parent, size_t bufsize,
struct sldns_buffer* spoolbuf, comm_point_callback_type* callback,
- void* callback_arg)
+ void* callback_arg, struct unbound_socket* socket)
{
struct comm_point* c = (struct comm_point*)calloc(1,
sizeof(struct comm_point));
@@ -3361,6 +3419,7 @@ comm_point_create_tcp_handler(struct comm_base *base,
c->repinfo.c = c;
c->callback = callback;
c->cb_arg = callback_arg;
+ c->socket = socket;
if(spoolbuf) {
c->tcp_req_info = tcp_req_info_create(spoolbuf);
if(!c->tcp_req_info) {
@@ -3400,7 +3459,8 @@ static struct comm_point*
comm_point_create_http_handler(struct comm_base *base,
struct comm_point* parent, size_t bufsize, int harden_large_queries,
uint32_t http_max_streams, char* http_endpoint,
- comm_point_callback_type* callback, void* callback_arg)
+ comm_point_callback_type* callback, void* callback_arg,
+ struct unbound_socket* socket)
{
struct comm_point* c = (struct comm_point*)calloc(1,
sizeof(struct comm_point));
@@ -3454,6 +3514,7 @@ comm_point_create_http_handler(struct comm_base *base,
c->repinfo.c = c;
c->callback = callback;
c->cb_arg = callback_arg;
+ c->socket = socket;
c->http_min_version = http_version_2;
c->http2_stream_max_qbuffer_size = bufsize;
@@ -3518,7 +3579,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num,
uint32_t http_max_streams, char* http_endpoint,
struct tcl_list* tcp_conn_limit, size_t bufsize,
struct sldns_buffer* spoolbuf, enum listen_type port_type,
- comm_point_callback_type* callback, void* callback_arg)
+ comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket)
{
struct comm_point* c = (struct comm_point*)calloc(1,
sizeof(struct comm_point));
@@ -3568,6 +3629,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num,
#endif
c->callback = NULL;
c->cb_arg = NULL;
+ c->socket = socket;
evbits = UB_EV_READ | UB_EV_PERSIST;
/* ub_event stuff */
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
@@ -3589,12 +3651,12 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num,
port_type == listen_type_ssl ||
port_type == listen_type_tcp_dnscrypt) {
c->tcp_handlers[i] = comm_point_create_tcp_handler(base,
- c, bufsize, spoolbuf, callback, callback_arg);
+ c, bufsize, spoolbuf, callback, callback_arg, socket);
} else if(port_type == listen_type_http) {
c->tcp_handlers[i] = comm_point_create_http_handler(
base, c, bufsize, harden_large_queries,
http_max_streams, http_endpoint,
- callback, callback_arg);
+ callback, callback_arg, socket);
}
else {
log_err("could not create tcp handler, unknown listen "
@@ -3895,11 +3957,13 @@ comm_point_close(struct comm_point* c)
/* close fd after removing from event lists, or epoll.. is messed up */
if(c->fd != -1 && !c->do_not_close) {
+#ifdef USE_WINSOCK
if(c->type == comm_tcp || c->type == comm_http) {
/* delete sticky events for the fd, it gets closed */
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
}
+#endif
verbose(VERB_ALGO, "close fd %d", c->fd);
sock_close(c->fd);
}
@@ -3970,20 +4034,26 @@ comm_point_send_reply(struct comm_reply *repinfo)
comm_point_send_udp_msg(repinfo->c, buffer,
(struct sockaddr*)&repinfo->addr, repinfo->addrlen, 0);
#ifdef USE_DNSTAP
- if(repinfo->c->dtenv != NULL &&
- repinfo->c->dtenv->log_client_response_messages)
- dt_msg_send_client_response(repinfo->c->dtenv,
- &repinfo->addr, repinfo->c->type, repinfo->c->buffer);
+ /*
+ * sending src (client)/dst (local service) addresses over DNSTAP from udp callback
+ */
+ if(repinfo->c->dtenv != NULL && repinfo->c->dtenv->log_client_response_messages) {
+ log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
+ log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen);
+ dt_msg_send_client_response(repinfo->c->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type, repinfo->c->buffer);
+ }
#endif
} else {
#ifdef USE_DNSTAP
- if(repinfo->c->tcp_parent->dtenv != NULL &&
- repinfo->c->tcp_parent->dtenv->log_client_response_messages)
- dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv,
- &repinfo->addr, repinfo->c->type,
- ( repinfo->c->tcp_req_info
- ? repinfo->c->tcp_req_info->spool_buffer
- : repinfo->c->buffer ));
+ /*
+ * sending src (client)/dst (local service) addresses over DNSTAP from TCP callback
+ */
+ if(repinfo->c->tcp_parent->dtenv != NULL && repinfo->c->tcp_parent->dtenv->log_client_response_messages) {
+ log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
+ log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen);
+ dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type,
+ ( repinfo->c->tcp_req_info? repinfo->c->tcp_req_info->spool_buffer: repinfo->c->buffer ));
+ }
#endif
if(repinfo->c->tcp_req_info) {
tcp_req_info_send_reply(repinfo->c->tcp_req_info);