...
 
Commits (23)
5473. [func] Netmgr server-side TLS layer and internal server-side
DoT support, currently unused. [GL #1840]
5472. [func] The statistics channel has been updated to use the
new network manager. [GL #2022]
......
......@@ -642,7 +642,6 @@ printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg,
if (yaml) {
enum { Q = 0x1, R = 0x2 }; /* Q:query; R:ecursive */
unsigned int tflag = 0;
isc_sockaddr_t saddr;
char sockstr[ISC_SOCKADDR_FORMATSIZE];
uint16_t sport;
char *hash;
......@@ -713,10 +712,9 @@ printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg,
printf(" response_port: %u\n", sport);
}
if (query->sock != NULL &&
isc_socket_getsockname(query->sock, &saddr) ==
ISC_R_SUCCESS)
{
if (query->handle != NULL) {
isc_sockaddr_t saddr =
isc_nmhandle_localaddr(query->handle);
sport = isc_sockaddr_getport(&saddr);
isc_sockaddr_format(&saddr, sockstr, sizeof(sockstr));
hash = strchr(sockstr, '#');
......@@ -1967,10 +1965,10 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
srcport = 0;
}
if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) {
isc_sockaddr_fromin6(&bind_address, &in6, srcport);
isc_sockaddr_fromin6(&localaddr, &in6, srcport);
isc_net_disableipv4();
} else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) {
isc_sockaddr_fromin(&bind_address, &in4, srcport);
isc_sockaddr_fromin(&localaddr, &in4, srcport);
isc_net_disableipv6();
} else {
if (hash != NULL) {
......
This diff is collapsed.
......@@ -168,7 +168,7 @@ struct dig_query {
unsigned int magic;
dig_lookup_t *lookup;
bool waiting_connect, pending_free, waiting_senddone, first_pass,
first_soa_rcvd, second_rr_rcvd, first_repeat_rcvd, recv_made,
first_soa_rcvd, second_rr_rcvd, first_repeat_rcvd,
warn_id, timedout;
uint32_t first_rr_serial;
uint32_t second_rr_serial;
......@@ -177,9 +177,9 @@ struct dig_query {
bool ixfr_axfr;
char *servname;
char *userarg;
isc_buffer_t recvbuf, lengthbuf, tmpsendbuf, sendbuf;
isc_buffer_t sendbuf;
char *recvspace, *tmpsendspace, lengthspace[4];
isc_socket_t *sock;
isc_nmhandle_t *handle;
ISC_LINK(dig_query_t) link;
ISC_LINK(dig_query_t) clink;
isc_sockaddr_t sockaddr;
......@@ -221,7 +221,7 @@ extern int sendcount;
extern int ndots;
extern int lookup_counter;
extern int exitcode;
extern isc_sockaddr_t bind_address;
extern isc_sockaddr_t localaddr;
extern char keynametext[MXNAME];
extern char keyfile[MXNAME];
extern char keysecret[MXNAME];
......
......@@ -942,13 +942,11 @@ flush_lookup_list(void) {
while (l != NULL) {
q = ISC_LIST_HEAD(l->q);
while (q != NULL) {
if (q->sock != NULL) {
isc_socket_cancel(q->sock, NULL,
ISC_SOCKCANCEL_ALL);
isc_socket_detach(&q->sock);
if (q->handle != NULL) {
isc_nm_cancelread(q->handle);
isc_nmhandle_unref(q->handle);
q->handle = NULL;
}
isc_buffer_invalidate(&q->recvbuf);
isc_buffer_invalidate(&q->lengthbuf);
qp = q;
q = ISC_LIST_NEXT(q, link);
ISC_LIST_DEQUEUE(l->q, qp, link);
......
......@@ -1003,7 +1003,7 @@ main(int argc, char **argv) {
isc_mem_create(&rndc_mctx);
netmgr = isc_nm_start(rndc_mctx, 1);
DO("create task manager",
isc_taskmgr_create(rndc_mctx, 1, 0, NULL, &taskmgr));
isc_taskmgr_create(rndc_mctx, 1, 0, netmgr, &taskmgr));
DO("create task", isc_task_create(taskmgr, 0, &rndc_task));
isc_log_create(rndc_mctx, &log, &logconfig);
isc_log_setcontext(log);
......
......@@ -103,15 +103,20 @@ status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking drop edns server setup ($n)"
ret=0
echo x
$DIG $DIGOPTS +edns @10.53.0.2 dropedns soa > dig.out.1.test$n && ret=1
echo x
grep "connection timed out; no servers could be reached" dig.out.1.test$n > /dev/null || ret=1
$DIG $DIGOPTS +noedns @10.53.0.2 dropedns soa > dig.out.2.test$n || ret=1
echo x
grep "status: NOERROR" dig.out.2.test$n > /dev/null || ret=1
grep "EDNS: version:" dig.out.2.test$n > /dev/null && ret=1
$DIG $DIGOPTS +noedns +tcp @10.53.0.2 dropedns soa > dig.out.3.test$n || ret=1
echo x
grep "status: NOERROR" dig.out.3.test$n > /dev/null || ret=1
grep "EDNS: version:" dig.out.3.test$n > /dev/null && ret=1
$DIG $DIGOPTS +edns +tcp @10.53.0.2 dropedns soa > dig.out.4.test$n && ret=1
echo x
grep "connection timed out; no servers could be reached" dig.out.4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
......
......@@ -26,12 +26,10 @@ $DIFF ref output > /dev/null && { ret=1 ; echo_i "diff out of order failed"; }
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
# flush resolver so queries will be from others again
$RNDCCMD 10.53.0.4 flush
sleep 1
echo_i "check pipelined TCP queries using mdig"
ret=0
$RNDCCMD 10.53.0.4 flush
sleep 1
$MDIG $MDIGOPTS +noall +answer +vc -f input -b 10.53.0.4 @10.53.0.4 > raw.mdig
awk '{ print $1 " " $5 }' < raw.mdig > output.mdig
sort < output.mdig > output-sorted.mdig
......@@ -42,6 +40,8 @@ status=`expr $status + $ret`
echo_i "check keep-response-order"
ret=0
$RNDCCMD 10.53.0.4 flush
sleep 1
$PIPEQUERIES -p ${PORT} ++ < inputb > rawb || ret=1
awk '{ print $1 " " $5 }' < rawb > outputb
$DIFF refb outputb || ret=1
......@@ -50,6 +50,8 @@ status=`expr $status + $ret`
echo_i "check keep-response-order using mdig"
ret=0
$RNDCCMD 10.53.0.4 flush
sleep 1
$MDIG $MDIGOPTS +noall +answer +vc -f inputb -b 10.53.0.7 @10.53.0.4 > rawb.mdig
awk '{ print $1 " " $5 }' < rawb.mdig > outputb.mdig
$DIFF refb outputb.mdig || ret=1
......@@ -58,6 +60,8 @@ status=`expr $status + $ret`
echo_i "check mdig -4 -6"
ret=0
$RNDCCMD 10.53.0.4 flush
sleep 1
$MDIG $MDIGOPTS -4 -6 -f input @10.53.0.4 > output46.mdig 2>&1 && ret=1
grep "only one of -4 and -6 allowed" output46.mdig > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
......
......@@ -8,11 +8,10 @@
# information regarding copyright ownership.
rm -f ns*/*.jnl
rm -f ns*/named.conf
rm -f ns*/named.lock
rm -f ns*/named.memstats
rm -f ns*/named.run
rm -f ns*/rpz*.txt
rm -f resolver/named.conf
rm -f */named.conf
rm -f */named.run
rm -rf __pycache__
rm -f *.status
logging {
channel basic {
file "named.run";
severity debug 999;
print-time yes;
};
category default { basic; };
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
......
......@@ -582,7 +582,7 @@ CRYPTO=OpenSSL
#
# OpenSSL/LibreSSL is mandatory
#
PKG_CHECK_MODULES([OPENSSL], [libcrypto], [],
PKG_CHECK_MODULES([OPENSSL], [libssl libcrypto], [],
[AX_CHECK_OPENSSL([:],[AC_MSG_FAILURE([OpenSSL/LibreSSL not found])])])
AX_SAVE_FLAGS([openssl])
......
......@@ -224,7 +224,7 @@ options {
listen-on-v6 [ port <integer> ] [ dscp
<integer> ] {
<address_match_element>; ... }; // may occur multiple times
lmdb-mapsize <sizeval>;
lmdb-mapsize <sizeval>; // non-operational
lock-file ( <quoted_string> | none );
maintain-ixfr-base <boolean>; // ancient
managed-keys-directory <quoted_string>;
......@@ -584,7 +584,7 @@ view <string> [ <class> ] {
}; // may occur multiple times
key-directory <quoted_string>;
lame-ttl <duration>;
lmdb-mapsize <sizeval>;
lmdb-mapsize <sizeval>; // non-operational
maintain-ixfr-base <boolean>; // ancient
managed-keys { <string> (
static-key | initial-key
......
......@@ -202,7 +202,7 @@ options {
listen-on-v6 [ port <integer> ] [ dscp
<integer> ] {
<address_match_element>; ... }; // may occur multiple times
lmdb-mapsize <sizeval>;
lmdb-mapsize <sizeval>; // non-operational
lock-file ( <quoted_string> | none );
managed-keys-directory <quoted_string>;
masterfile-format ( map | raw | text );
......@@ -525,7 +525,7 @@ view <string> [ <class> ] {
}; // may occur multiple times
key-directory <quoted_string>;
lame-ttl <duration>;
lmdb-mapsize <sizeval>;
lmdb-mapsize <sizeval>; // non-operational
managed-keys { <string> (
static-key | initial-key
| static-ds | initial-ds
......
......@@ -126,6 +126,7 @@ libisc_la_SOURCES = \
netmgr/netmgr.c \
netmgr/tcp.c \
netmgr/tcpdns.c \
netmgr/tls.c \
netmgr/udp.c \
netmgr/uv-compat.c \
netmgr/uv-compat.h \
......
......@@ -16,6 +16,8 @@
#include <isc/result.h>
#include <isc/types.h>
#include <openssl/ssl.h>
/*
* Replacement for isc_sockettype_t provided by socket.h.
*/
......@@ -176,8 +178,21 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
* as its argument.
*
* When handles are allocated for the socket, 'extrasize' additional bytes
* will be allocated along with the handle for an associated object
* (typically ns_client).
* can be allocated along with the handle for an associated object, which
* can then be freed automatically when the handle is destroyed.
*/
isc_result_t
isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, size_t extrahandlesize);
/*%<
* Open a UDP socket, bind to 'local' and connect to 'peer', and
* immediately call 'cb' with a handle so that the caller can begin
* sending packets over UDP.
*
* When handles are allocated for the socket, 'extrasize' additional bytes
* can be allocated along with the handle for an associated object, which
* can then be freed automatically when the handle is destroyed.
*/
void
......@@ -196,12 +211,17 @@ isc_nm_pause(isc_nm_t *mgr);
void
isc_nm_resume(isc_nm_t *mgr);
/*%<
* Resume paused processing. It will return immediately
* after signalling workers to resume.
* Resume paused processing. It will return immediately after signalling
* workers to resume.
*/
isc_result_t
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
/*
* Begin (or continue) reading on the socket associated with 'handle', and
* update its recv callback to 'cb', which will be called as soon as there
* is data to process.
*/
isc_result_t
isc_nm_pauseread(isc_nmhandle_t *handle);
......@@ -289,7 +309,8 @@ isc_result_t
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
void *cbarg, isc_nm_accept_cb_t accept_cb,
void *accept_cbarg, size_t extrahandlesize, int backlog,
isc_quota_t *quota, isc_nmsocket_t **sockp);
isc_quota_t *quota, SSL_CTX *sslctx,
isc_nmsocket_t **sockp);
/*%<
* Start listening for DNS messages over the TCP interface 'iface', using
* net manager 'mgr'.
......@@ -367,6 +388,17 @@ isc_nm_tcp_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle,
* \li 'mgr' is a valid netmgr.
*/
isc_result_t
isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
size_t extrahandlesize, int backlog, isc_quota_t *quota,
SSL_CTX *sslctx, isc_nmsocket_t **sockp);
isc_result_t
isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, SSL_CTX *ctx,
size_t extrahandlesize);
void
isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp);
/*%<
......@@ -385,3 +417,7 @@ isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats);
*\li stats is a valid set of statistics counters supporting the
* full range of socket-related stats counter numbers.
*/
isc_result_t
isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, size_t extrahandlesize);
......@@ -88,6 +88,7 @@
#define ISC_R_DISCFULL 67 /*%< disc full */
#define ISC_R_DEFAULT 68 /*%< default */
#define ISC_R_IPV4PREFIX 69 /*%< IPv4 prefix */
#define ISC_R_TLSERROR 70 /*%< TLS error */
/*% Not a result code: the number of results. */
#define ISC_R_NRESULTS 70
......
......@@ -14,6 +14,9 @@
#include <unistd.h>
#include <uv.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <isc/astack.h>
#include <isc/atomic.h>
#include <isc/buffer.h>
......@@ -116,13 +119,14 @@ struct isc_nmiface {
};
typedef enum isc__netievent_type {
netievent_udpconnect,
netievent_udpsend,
netievent_udprecv,
netievent_udpread,
netievent_udpstop,
netievent_udpclose,
netievent_tcpconnect,
netievent_tcpsend,
netievent_tcprecv,
netievent_tcpstartread,
netievent_tcppauseread,
netievent_tcpchildaccept,
......@@ -130,8 +134,14 @@ typedef enum isc__netievent_type {
netievent_tcpstop,
netievent_tcpclose,
netievent_tcpdnsclose,
netievent_tcpdnssend,
netievent_tcpdnsread,
netievent_tcpdnsclose,
netievent_tlsclose,
netievent_tlssend,
netievent_tlsstartread,
netievent_tlsconnect,
netievent_closecb,
netievent_shutdown,
......@@ -146,20 +156,12 @@ typedef enum isc__netievent_type {
netievent_tcplisten,
} isc__netievent_type;
/*
* We have to split it because we can read and write on a socket
* simultaneously.
*/
typedef union {
isc_nm_recv_cb_t recv;
isc_nm_cb_t connect;
isc_nm_accept_cb_t accept;
} isc__nm_readcb_t;
typedef union {
isc_nm_cb_t send;
isc_nm_cb_t connect;
} isc__nm_writecb_t;
typedef union {
isc_nm_recv_cb_t recv;
isc_nm_accept_cb_t accept;
......@@ -206,13 +208,18 @@ typedef struct isc__netievent__socket {
} isc__netievent__socket_t;
typedef isc__netievent__socket_t isc__netievent_udplisten_t;
typedef isc__netievent__socket_t isc__netievent_udpread_t;
typedef isc__netievent__socket_t isc__netievent_udpstop_t;
typedef isc__netievent__socket_t isc__netievent_udpclose_t;
typedef isc__netievent__socket_t isc__netievent_tcpstop_t;
typedef isc__netievent__socket_t isc__netievent_tcpclose_t;
typedef isc__netievent__socket_t isc__netievent_tlsclose_t;
typedef isc__netievent__socket_t isc__netievent_tcpdnsclose_t;
typedef isc__netievent__socket_t isc__netievent_startread_t;
typedef isc__netievent__socket_t isc__netievent_pauseread_t;
typedef isc__netievent__socket_t isc__netievent_closecb_t;
typedef isc__netievent__socket_t isc__netievent_tcpdnsclose_t;
typedef isc__netievent__socket_t isc__netievent_tcpdnsread_t;
typedef struct isc__netievent__socket_req {
isc__netievent_type type;
......@@ -256,6 +263,20 @@ typedef struct isc__netievent_udpsend {
isc__nm_uvreq_t *req;
} isc__netievent_udpsend_t;
typedef struct isc__netievent_udpconnect {
isc__netievent_type type;
isc_nmsocket_t *sock;
isc_sockaddr_t peer;
} isc__netievent_udpconnect_t;
typedef struct isc__netievent_tlsconnect {
isc__netievent_type type;
isc_nmsocket_t *sock;
SSL_CTX *ctx;
isc_sockaddr_t local; /* local address */
isc_sockaddr_t peer; /* peer address */
} isc__netievent_tlsconnect_t;
typedef struct isc__netievent {
isc__netievent_type type;
} isc__netievent_t;
......@@ -333,7 +354,9 @@ typedef enum isc_nmsocket_type {
isc_nm_tcpsocket,
isc_nm_tcplistener,
isc_nm_tcpdnslistener,
isc_nm_tcpdnssocket
isc_nm_tcpdnssocket,
isc_nm_tlslistener,
isc_nm_tlssocket
} isc_nmsocket_type;
/*%
......@@ -371,6 +394,16 @@ struct isc_nmsocket {
/*% Self, for self-contained unreferenced sockets (tcpdns) */
isc_nmsocket_t *self;
/*% TLS stuff */
struct tls {
bool server;
BIO *app_bio;
SSL *ssl;
SSL_CTX *ctx;
BIO *ssl_bio;
enum { INIT, HANDSHAKE, IO, CLOSING } state;
} tls;
/*%
* quota is the TCP client, attached when a TCP connection
* is established. pquota is a non-attached pointer to the
......@@ -403,7 +436,7 @@ struct isc_nmsocket {
isc_nmsocket_t *children;
int nchildren;
isc_nmiface_t *iface;
isc_nmhandle_t *tcphandle;
isc_nmhandle_t *statichandle;
isc_nmhandle_t *outerhandle;
/*% Extra data allocated at the end of each isc_nmhandle_t */
......@@ -445,7 +478,12 @@ struct isc_nmsocket {
isc_refcount_t references;
/*%
* TCPDNS socket has been set not to pipeliine.
* Established an outgoing connection, as client not server.
*/
atomic_bool client;
/*%
* TCPDNS socket has been set not to pipeline.
*/
atomic_bool sequential;
......@@ -673,16 +711,40 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
* Back-end implementation of isc_nm_send() for UDP handles.
*/
isc_result_t
isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
/*
* Back-end implementation of isc_nm_read() for UDP handles.
*/
void
isc__nm_udp_close(isc_nmsocket_t *sock);
/*%<
* Close a UDP socket.
*/
void
isc__nm_udp_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_udp_cancelread(isc_nmhandle_t *handle);
/*%<
* Stop reading on a pending UDP handle.
*/
void
isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpstop(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_udpclose(isc__networker_t *worker, isc__netievent_t *ev0);
/*%<
* Callback handlers for asynchronous UDP events (listen, stoplisten, send).
*/
......@@ -696,6 +758,9 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
isc_result_t
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
/*
* Back-end implementation of isc_nm_read() for TCP handles.
*/
void
isc__nm_tcp_close(isc_nmsocket_t *sock);
......@@ -723,9 +788,9 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock);
*/
void
isc__nm_tcp_cancelread(isc_nmsocket_t *sock);
isc__nm_tcp_cancelread(isc_nmhandle_t *handle);
/*%<
* Stop reading on a connected socket.
* Stop reading on a connected TCP handle.
*/
void
......@@ -758,6 +823,22 @@ isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0);
* stoplisten, send, read, pause, close).
*/
void
isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tls_startread(isc__networker_t *worker, isc__netievent_t *ev0);
/*%<
* Callback handlers for asynchronouse TLS events.
*/
isc_result_t
isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
......@@ -780,6 +861,46 @@ isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0);
isc_result_t
isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
void
isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle);
/*%<
* Stop reading on a connected TCPDNS handle.
*/
isc_result_t
isc__nm_tls_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg);
isc_result_t
isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
void
isc__nm_tls_close(isc_nmsocket_t *sock);
/*%<
* Close a TLS socket.
*/
isc_result_t
isc__nm_tls_pauseread(isc_nmsocket_t *sock);
/*%<
* Pause reading on this socket, while still remembering the callback.
*/
isc_result_t
isc__nm_tls_resumeread(isc_nmsocket_t *sock);
/*%<
* Resume reading from socket.
*
*/
void
isc__nm_tls_stoplistening(isc_nmsocket_t *sock);
#define isc__nm_uverr2result(x) \
isc___nm_uverr2result(x, true, __FILE__, __LINE__)
isc_result_t
......
......@@ -393,6 +393,7 @@ isc_nm_closedown(isc_nm_t *mgr) {
void
isc_nm_destroy(isc_nm_t **mgr0) {
isc_nm_t *mgr = NULL;
int counter = 0;
REQUIRE(mgr0 != NULL);
REQUIRE(VALID_NM(*mgr0));
......@@ -407,7 +408,8 @@ isc_nm_destroy(isc_nm_t **mgr0) {
/*
* Wait for the manager to be dereferenced elsewhere.
*/
while (isc_refcount_current(&mgr->references) > 1) {
while (isc_refcount_current(&mgr->references) > 1 &&
counter++ < 1000) {
/*
* Sometimes libuv gets stuck, pausing and unpausing
* netmgr goes over all events in async queue for all
......@@ -423,6 +425,8 @@ isc_nm_destroy(isc_nm_t **mgr0) {
#endif /* ifdef WIN32 */
}
INSIST(counter <= 1000);
/*
* Detach final reference.
*/
......@@ -591,6 +595,10 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
uv_stop(&worker->loop);
isc_mempool_put(worker->mgr->evpool, ievent);
return;
case netievent_udpconnect:
isc__nm_async_udpconnect(worker, ievent);
break;
case netievent_udplisten:
isc__nm_async_udplisten(worker, ievent);
break;
......@@ -600,6 +608,14 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
case netievent_udpsend:
isc__nm_async_udpsend(worker, ievent);
break;
case netievent_udpread:
isc__nm_async_udpread(worker, ievent);
break;
case netievent_udpclose:
isc__nm_async_udpclose(worker, ievent);
break;
case netievent_tcpconnect:
isc__nm_async_tcpconnect(worker, ievent);
break;
......@@ -630,9 +646,27 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
case netievent_tcpclose:
isc__nm_async_tcpclose(worker, ievent);
break;
case netievent_tlsstartread:
isc__nm_async_tls_startread(worker, ievent);
break;
case netievent_tlssend:
isc__nm_async_tlssend(worker, ievent);
break;
case netievent_tlsclose:
isc__nm_async_tlsclose(worker, ievent);
break;
case netievent_tlsconnect:
isc__nm_async_tlsconnect(worker, ievent);
break;
case netievent_tcpdnsclose:
isc__nm_async_tcpdnsclose(worker, ievent);
break;
case netievent_tcpdnsread:
isc__nm_async_tcpdnsread(worker, ievent);
break;
case netievent_closecb:
isc__nm_async_closecb(worker, ievent);
break;
......@@ -739,7 +773,7 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree) {
isc__nm_decstats(sock->mgr, sock->statsindex[STATID_ACTIVE]);
}
sock->tcphandle = NULL;
sock->statichandle = NULL;
if (sock->outerhandle != NULL) {
isc_nmhandle_unref(sock->outerhandle);
......@@ -833,7 +867,7 @@ nmsocket_maybe_destroy(isc_nmsocket_t *sock) {
}
}
if (active_handles == 0 || sock->tcphandle != NULL) {
if (active_handles == 0 || sock->statichandle != NULL) {
destroy = true;
}
......@@ -875,12 +909,18 @@ isc__nmsocket_prep_destroy(isc_nmsocket_t *sock) {
*/
if (!atomic_load(&sock->closed)) {
switch (sock->type) {
case isc_nm_udpsocket:
isc__nm_udp_close(sock);
return;
case isc_nm_tcpsocket:
isc__nm_tcp_close(sock);
return;
case isc_nm_tcpdnssocket:
isc__nm_tcpdns_close(sock);
return;
case isc_nm_tlssocket:
isc__nm_tls_close(sock);
break;
default:
break;
}
......@@ -1116,9 +1156,10 @@ isc__nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
handle->ah_pos = pos;
UNLOCK(&sock->lock);
if (sock->type == isc_nm_tcpsocket) {
INSIST(sock->tcphandle == NULL);
sock->tcphandle = handle;
if (sock->type == isc_nm_tcpsocket || sock->type == isc_nm_tlssocket ||
(sock->type == isc_nm_udpsocket && sock->client)) {
INSIST(sock->statichandle == NULL);
sock->statichandle = handle;
}
return (handle);
......@@ -1225,6 +1266,10 @@ isc_nmhandle_unref(isc_nmhandle_t *handle) {
}
}
if (handle == sock->statichandle) {
sock->statichandle = NULL;
}
isc__nmsocket_detach(&sock);
}
......@@ -1345,6 +1390,8 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
return (isc__nm_tcp_send(handle, region, cb, cbarg));
case isc_nm_tcpdnssocket:
return (isc__nm_tcpdns_send(handle, region, cb, cbarg));
case isc_nm_tlssocket:
return (isc__nm_tls_send(handle, region, cb, cbarg));
default:
INSIST(0);
ISC_UNREACHABLE();
......@@ -1356,8 +1403,14 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));
switch (handle->sock->type) {
case isc_nm_udpsocket:
return (isc__nm_udp_read(handle, cb, cbarg));
case isc_nm_tcpsocket:
return (isc__nm_tcp_read(handle, cb, cbarg));
case isc_nm_tcpdnssocket:
return (isc__nm_tcpdns_read(handle, cb, cbarg));
case isc_nm_tlssocket:
return (isc__nm_tls_read(handle, cb, cbarg));
default:
INSIST(0);
ISC_UNREACHABLE();
......@@ -1369,8 +1422,14 @@ isc_nm_cancelread(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
switch (handle->sock->type) {
case isc_nm_udpsocket:
isc__nm_udp_cancelread(handle);
break;
case isc_nm_tcpsocket:
isc__nm_tcp_cancelread(handle->sock);
isc__nm_tcp_cancelread(handle);
break;
case isc_nm_tcpdnssocket:
isc__nm_tcpdns_cancelread(handle);
break;
default:
INSIST(0);
......@@ -1387,6 +1446,8 @@ isc_nm_pauseread(isc_nmhandle_t *handle) {
switch (sock->type) {
case isc_nm_tcpsocket:
return (isc__nm_tcp_pauseread(sock));
case isc_nm_tlssocket:
return (isc__nm_tls_pauseread(sock));
default:
INSIST(0);
ISC_UNREACHABLE();
......@@ -1402,6 +1463,8 @@ isc_nm_resumeread(isc_nmhandle_t *handle) {
switch (sock->type) {
case isc_nm_tcpsocket:
return (isc__nm_tcp_resumeread(sock));
case isc_nm_tlssocket:
return (isc__nm_tls_resumeread(sock));
default:
INSIST(0);
ISC_UNREACHABLE();
......@@ -1422,6 +1485,9 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) {
case isc_nm_tcplistener:
isc__nm_tcp_stoplistening(sock);
break;
case isc_nm_tlslistener:
isc__nm_tls_stoplistening(sock);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
......
......@@ -147,49 +147,46 @@ done:
static void
tcp_connect_cb(uv_connect_t *uvreq, int status) {
isc_result_t result;
isc__nm_uvreq_t *req = (isc__nm_uvreq_t *)uvreq->data;
isc_nmsocket_t *sock = NULL;
struct sockaddr_storage ss;
isc_nmhandle_t *handle = NULL;
sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
REQUIRE(VALID_UVREQ(req));
if (status == 0) {
isc_result_t result;
struct sockaddr_storage ss;
isc_nmhandle_t *handle = NULL;
if (status != 0) {
req->cb.connect(NULL, isc__nm_uverr2result(status), req->cbarg);
isc__nm_uvreq_put(&req, sock);
return;
}
sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]);
uv_tcp_getpeername(&sock->uv_handle.tcp, (struct sockaddr *)&ss,
&(int){ sizeof(ss) });
result = isc_sockaddr_fromsockaddr(&sock->peer,
(struct sockaddr *)&ss);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]);
uv_tcp_getpeername(&sock->uv_handle.tcp, (struct sockaddr *)&ss,
&(int){ sizeof(ss) });
result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
handle = isc__nmhandle_get(sock, NULL, NULL);
req->cb.connect(handle, ISC_R_SUCCESS, req->cbarg);
handle = isc__nmhandle_get(sock, NULL, NULL);
req->cb.connect(handle, ISC_R_SUCCESS, req->cbarg);
isc__nm_uvreq_put(&req, sock);
isc__nm_uvreq_put(&req, sock);
/*
* The sock is now attached to the handle.
*/
isc__nmsocket_detach(&sock);
sock->client = true;
/*
* If the connect callback wants to hold on to the handle,
* it needs to attach to it.
*/
isc_nmhandle_unref(handle);
} else {
/*
* TODO:
* Handle the connect error properly and free the socket.
*/
req->cb.connect(NULL, isc__nm_uverr2result(status), req->cbarg);
isc__nm_uvreq_put(&req, sock);
}
/*
* The sock is now attached to the handle.
*/
isc__nmsocket_detach(&sock);
/*
* If the connect callback wants to hold on to the handle,
* it needs to attach to it.
*/
isc_nmhandle_unref(handle);
}
isc_result_t
......@@ -201,6 +198,8 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
REQUIRE(peer != NULL);
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
isc__nmsocket_init(nsock, mgr, isc_nm_tcpsocket, local);
......@@ -211,6 +210,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
req->cb.connect = cb;
req->cbarg = cbarg;
req->peer = peer->addr;
req->local = local->addr;
ievent = isc__nm_get_ievent(mgr, netievent_tcpconnect);
ievent->sock = nsock;
......@@ -591,7 +591,7 @@ readtimeout_cb(uv_timer_t *handle) {
isc_quota_detach(&sock->quota);
}
if (sock->rcb.recv != NULL) {
sock->rcb.recv(sock->tcphandle, ISC_R_TIMEDOUT, NULL,
sock->rcb.recv(sock->statichandle, ISC_R_TIMEDOUT, NULL,
sock->rcbarg);
isc__nmsocket_clearcb(sock);
}
......@@ -729,8 +729,8 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
.length = nread };
if (sock->rcb.recv != NULL) {
sock->rcb.recv(sock->tcphandle, ISC_R_SUCCESS, &region,
sock->rcbarg);
sock->rcb.recv(sock->statichandle, ISC_R_SUCCESS,
&region, sock->rcbarg);
}
sock->read_timeout = (atomic_load(&sock->keepalive)
......@@ -755,7 +755,8 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
*/
if (sock->rcb.recv != NULL) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_RECVFAIL]);
sock->rcb.recv(sock->tcphandle, ISC_R_EOF, NULL, sock->rcbarg);
sock->rcb.recv(sock->statichandle, ISC_R_EOF, NULL,
sock->rcbarg);
isc__nmsocket_clearcb(sock);
}
......@@ -1088,24 +1089,27 @@ void
isc__nm_tcp_shutdown(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
if (sock->type == isc_nm_tcpsocket && sock->tcphandle != NULL &&
if (sock->type == isc_nm_tcpsocket && sock->statichandle != NULL &&
sock->rcb.recv != NULL)
{
sock->rcb.recv(sock->tcphandle, ISC_R_CANCELED, NULL,
sock->rcb.recv(sock->statichandle, ISC_R_CANCELED, NULL,
sock->rcbarg);
isc__nmsocket_clearcb(sock);
}
}
void
isc__nm_tcp_cancelread(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
isc__nm_tcp_cancelread(isc_nmhandle_t *handle) {
isc_nmsocket_t *sock = NULL;
if (sock->type == isc_nm_tcpsocket && sock->tcphandle != NULL &&
sock->rcb.recv != NULL)
{
sock->rcb.recv(sock->tcphandle, ISC_R_CANCELED, NULL,
sock->rcbarg);
REQUIRE(VALID_NMHANDLE(handle));
sock = handle->sock;
REQUIRE(sock->type == isc_nm_tcpsocket);
if (sock->client && sock->rcb.recv != NULL) {
sock->rcb.recv(handle, ISC_R_EOF, NULL, sock->rcbarg);
isc__nmsocket_clearcb(sock);
}
}
......@@ -82,7 +82,9 @@ alloc_dnsbuf(isc_nmsocket_t *sock, size_t len) {
static void
timer_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = (isc_nmsocket_t *)uv_handle_get_data(handle);
INSIST(VALID_NMSOCK(sock));
REQUIRE(VALID_NMSOCK(sock));
atomic_store(&sock->closed, true);
tcpdns_close_direct(sock);
}
......@@ -94,7 +96,8 @@ dnstcp_readtimeout(uv_timer_t *timer) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
/* Close the TCP connection, it's closing should fire 'our' closing */
/* Close the TCP connection; its closure should fire ours. */
isc_nmhandle_unref(sock->outerhandle);
sock->outerhandle = NULL;
}
......@@ -187,8 +190,14 @@ processbuffer(isc_nmsocket_t *dnssock, isc_nmhandle_t **handlep) {
*/
len = dnslen(dnssock->buf);
if (len <= dnssock->buf_len - 2) {
isc_nmhandle_t *dnshandle = isc__nmhandle_get(dnssock, NULL,
NULL);
isc_nmhandle_t *dnshandle;
if (dnssock->client && dnssock->statichandle != NULL) {
dnshandle = dnssock->statichandle;
isc_nmhandle_ref(dnshandle);
} else {
dnshandle = isc__nmhandle_get(dnssock, NULL, NULL);
}
isc_nmsocket_t *listener = dnssock->listener;
if (listener != NULL && listener->rcb.recv != NULL) {
......@@ -197,6 +206,20 @@ processbuffer(isc_nmsocket_t *dnssock, isc_nmhandle_t **handlep) {
&(isc_region_t){ .base = dnssock->buf + 2,
.length = len },
listener->rcbarg);
} else if (dnssock->rcb.recv != NULL) {
isc_nm_recv_cb_t cb = dnssock->rcb.recv;
void *cbarg = dnssock->rcbarg;
/*
* We need to clear the read callback *before*
* calling it, because it might make another
* call to isc_nm_read() and set up a new callback.
*/
isc__nmsocket_clearcb(dnssock);
cb(dnshandle, ISC_R_SUCCESS,
&(isc_region_t){ .base = dnssock->buf + 2,
.length = len },
cbarg);
}
len += 2;
......@@ -227,11 +250,12 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
REQUIRE(VALID_NMSOCK(dnssock));
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(dnssock->tid == isc_nm_tid());
if (region == NULL || eresult != ISC_R_SUCCESS) {
/* Connection closed */
isc_nmhandle_unref(handle);
if (eresult != ISC_R_CANCELED) {
isc_nmhandle_unref(handle);
}
dnssock->result = eresult;
if (dnssock->self != NULL) {
isc__nmsocket_detach(&dnssock->self);
......@@ -277,11 +301,14 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
uv_timer_stop(&dnssock->timer);
}
if (atomic_load(&dnssock->sequential)) {
if (atomic_load(&dnssock->sequential) ||
dnssock->rcb.recv == NULL) {
/*
* We're in sequential mode and we processed
* one packet, so we're done until the next read
* completes.
* Two reasons we might want to pause here:
* - If we're in sequential mode and we've received
* a whole packet, so we're done until it's been
* processed;
* - If we no longer have a read callback.
*/
isc_nm_pauseread(dnssock->outerhandle);
done = true;
......@@ -313,7 +340,8 @@ isc_result_t
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
void *cbarg, isc_nm_accept_cb_t accept_cb,
void *accept_cbarg, size_t extrahandlesize, int backlog,
isc_quota_t *quota, isc_nmsocket_t **sockp) {
isc_quota_t *quota, SSL_CTX *sslctx,
isc_nmsocket_t **sockp) {
/* A 'wrapper' socket object with outer set to true TCP socket */
isc_nmsocket_t *dnslistensock = isc_mem_get(mgr->mctx,
sizeof(*dnslistensock));
......@@ -329,9 +357,16 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
dnslistensock->extrahandlesize = extrahandlesize;
/* We set dnslistensock->outer to a true listening socket */
result = isc_nm_listentcp(mgr, iface, dnslisten_acceptcb, dnslistensock,
extrahandlesize, backlog, quota,
&dnslistensock->outer);
if (sslctx != NULL) {
result = isc_nm_listentls(mgr, iface, dnslisten_acceptcb,
dnslistensock, extrahandlesize,
backlog, quota, sslctx,
&dnslistensock->outer);
} else {
result = isc_nm_listentcp(
mgr, iface, dnslisten_acceptcb, dnslistensock,
extrahandlesize, backlog, quota, &dnslistensock->outer);
}
if (result == ISC_R_SUCCESS) {
atomic_store(&dnslistensock->listening, true);
*sockp = dnslistensock;
......@@ -495,7 +530,7 @@ isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
r.base = (unsigned char *)req->uvbuf.base;
r.length = req->uvbuf.len;
result = isc__nm_tcp_send(sock->outerhandle, &r, tcpdnssend_cb,
result = isc_nm_send(sock->outerhandle, &r, tcpdnssend_cb,
req);
}
......@@ -538,7 +573,7 @@ isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
r.base = (unsigned char *)uvreq->uvbuf.base;
r.length = uvreq->uvbuf.len;
return (isc__nm_tcp_send(sock->outerhandle, &r, tcpdnssend_cb,
return (isc_nm_send(sock->outerhandle, &r, tcpdnssend_cb,
uvreq));
} else {
isc__netievent_tcpdnssend_t *ievent = NULL;
......@@ -616,3 +651,164 @@ isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0) {
tcpdns_close_direct(ievent->sock);
}
typedef struct tcpconnect {
isc_mem_t *mctx;
isc_nm_cb_t cb;
void *cbarg;
size_t extrahandlesize;
} tcpconnect_t;
static void
tcpdnsconnect_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
tcpconnect_t *conn = (tcpconnect_t *)arg;
isc_nm_cb_t cb = conn->cb;
void *cbarg = conn->cbarg;
size_t extrahandlesize = conn->extrahandlesize;
isc_mem_putanddetach(&conn->mctx, conn, sizeof(*conn));
if (result != ISC_R_SUCCESS) {
cb(NULL, result, cbarg);
return;
}
INSIST(VALID_NMHANDLE(handle));
isc_nmsocket_t *dnssock = isc_mem_get(handle->sock->mgr->mctx,
sizeof(*dnssock));
isc__nmsocket_init(dnssock, handle->sock->mgr, isc_nm_tcpdnssocket,
handle->sock->iface);
dnssock->extrahandlesize = extrahandlesize;
dnssock->outerhandle = handle;
isc_nmhandle_ref(dnssock->outerhandle);
dnssock->peer = handle->sock->peer;
dnssock->read_timeout = handle->sock->mgr->init;
dnssock->tid = isc_nm_tid();
dnssock->client = true;
dnssock->statichandle = isc__nmhandle_get(dnssock, NULL, NULL);
uv_timer_init(&dnssock->mgr->workers[isc_nm_tid()].loop,
&dnssock->timer);
dnssock->timer.data = dnssock;
dnssock->timer_initialized = true;
uv_timer_start(&dnssock->timer, dnstcp_readtimeout,
dnssock->read_timeout, 0);
/*
* We start reading not asked to - we'll read and buffer
* at most one packet.
*/
result = isc_nm_read(handle, dnslisten_readcb, dnssock);
if (result != ISC_R_SUCCESS) {
isc_nmhandle_unref(handle);
}
cb(dnssock->statichandle, ISC_R_SUCCESS, cbarg);
isc_nmhandle_unref(dnssock->statichandle);
isc__nmsocket_detach(&dnssock);
}
isc_result_t
isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, size_t extrahandlesize) {
tcpconnect_t *conn = isc_mem_get(mgr->mctx, sizeof(tcpconnect_t));
*conn = (tcpconnect_t){ .cb = cb,
.cbarg = cbarg,
.extrahandlesize = extrahandlesize };
isc_mem_attach(mgr->mctx, &conn->mctx);
SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
return (isc_nm_tlsconnect(mgr, local, peer, tcpdnsconnect_cb, conn, ctx, 0));
}
isc_result_t
isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
isc_nmsocket_t *sock = handle->sock;
isc__netievent_tcpdnsread_t *ievent = NULL;
REQUIRE(handle == sock->statichandle);
REQUIRE(sock->rcb.recv == NULL);
REQUIRE(sock->client);
/*
* This MUST be done asynchronously, no matter which thread we're
* in. The callback function for isc_nm_read() often calls
* isc_nm_read() again; if we tried to do that synchronously
* we'd clash in processbuffer() and grow the stack indefinitely.
*/
ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpdnsread);
ievent->sock = sock;
sock->rcb.recv = cb;
sock->rcbarg = cbarg;
isc_nmhandle_ref(handle);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
return (ISC_R_SUCCESS);
}
void
isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc_result_t result;
isc__netievent_tcpdnsread_t *ievent =
(isc__netievent_tcpdnsclose_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc_nmhandle_t *handle = NULL, *newhandle = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(worker->id == sock->tid);
handle = sock->statichandle;
if (sock->type != isc_nm_tcpdnssocket || sock->outerhandle == NULL) {
sock->rcb.recv(handle, ISC_R_NOTCONNECTED, NULL, sock->rcbarg);
isc_nmhandle_unref(handle);
return;
}
/*
* Maybe we have a packet already?
*/
result = processbuffer(sock, &newhandle);
if (result == ISC_R_SUCCESS) {
atomic_store(&sock->outerhandle->sock->processing, true);
if (sock->timer_initialized) {
uv_timer_stop(&sock->timer);
}
isc_nmhandle_unref(newhandle);
} else if (sock->outerhandle != NULL) {
/* Restart reading, wait for the callback */
atomic_store(&sock->outerhandle->sock->processing, false);
if (sock->timer_initialized) {
uv_timer_start(&sock->timer, dnstcp_readtimeout,
sock->read_timeout, 0);
}
isc_nm_resumeread(sock->outerhandle);
} else {
isc_nm_recv_cb_t cb = sock->rcb.recv;
void *cbarg = sock->rcbarg;
isc__nmsocket_clearcb(sock);
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
}
isc_nmhandle_unref(handle);
}
void
isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle) {
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
sock = handle->sock;
REQUIRE(sock->type == isc_nm_tcpdnssocket);
if (sock->client && sock->rcb.recv != NULL) {
sock->rcb.recv(handle, ISC_R_EOF, NULL, sock->rcbarg);
isc__nmsocket_clearcb(sock);
isc__nm_tcp_cancelread(sock->outerhandle);
}
}
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#include <libgen.h>
#include <unistd.h>
#include <uv.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <isc/atomic.h>
#include <isc/buffer.h>
#include <isc/condition.h>
#include <isc/log.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/quota.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
#include <isc/stdtime.h>
#include <isc/thread.h>
#include <isc/util.h>
#include "netmgr-int.h"
#include "uv-compat.h"
#define TLS_CHECK_RV INT_MAX
static void
tls_do_bio(isc_nmsocket_t *sock, int rv);
static void
tls_close_direct(isc_nmsocket_t *sock);
static void
tls_senddone(isc_nmhandle_t *t, isc_result_t res, void *arg) {
(void)res;
(void)t;
isc_nmsocket_t *sock = (isc_nmsocket_t *)arg;
/* if (sock->tls.state != IO) {
int rv = SSL_is_init_finished(sock->tls.ssl);
if (rv != 1) {
}
} */
tls_do_bio(sock, TLS_CHECK_RV);
}
static void
tls_do_bio(isc_nmsocket_t *sock, int rv) {
INSIST(sock->tid == isc_nm_tid());
isc_result_t result = ISC_R_SUCCESS;
if (rv == TLS_CHECK_RV) {
char buf[1];
rv = SSL_peek(sock->tls.ssl, buf, 1);
if (rv == 1) {
if (sock->rcb.recv != NULL &&
!atomic_load(&sock->readpaused)) {
isc_region_t region = { malloc(4096), 4096 };
memset(region.base, 0, region.length);
rv = SSL_read(sock->tls.ssl, region.base,
region.length);
isc_region_t dregion =
(isc_region_t){ region.base, rv };
sock->rcb.recv(sock->statichandle, ISC_R_SUCCESS,
&dregion, sock->rcbarg);
free(region.base);
}
}
}
int pending = BIO_pending(sock->tls.app_bio);
if (pending > 0) {
char *p = malloc(pending);
rv = BIO_read(sock->tls.app_bio, p, pending);
result = isc_nm_send(sock->outerhandle,
&(isc_region_t){ (unsigned char *)p, rv },
tls_senddone, sock);
if (result != ISC_R_SUCCESS) {
goto error;
}
}
int err = SSL_get_error(sock->tls.ssl, rv);
printf("SSL ERR %d\n", err);
if (err == 0) {
return;
} else if (err == SSL_ERROR_WANT_WRITE) {
isc_nm_pauseread(sock->outerhandle);
pending = BIO_pending(sock->tls.app_bio);
if (pending > 0) {
char *p = malloc(pending);
rv = BIO_read(sock->tls.app_bio, p, pending);
result = isc_nm_send(
sock->outerhandle,
&(isc_region_t){ (unsigned char *)p, rv },
tls_senddone, sock);
if (result != ISC_R_SUCCESS) {
goto error;
}
}
} else if (err == SSL_ERROR_WANT_READ) {
isc_nm_resumeread(sock->outerhandle);
} else {
goto error;
}
return;
error:
/* XXXWPK TODO log it ! */
printf("ERROR!\n");
if (sock->rcb.recv != NULL) {
sock->rcb.recv(sock->statichandle, result, NULL,
sock->rcbarg);
} else {
tls_close_direct(sock);
}
}
static void
tls_readcb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
void *arg) {
isc_nmsocket_t *tlssock = (isc_nmsocket_t *)arg;
int rv;
REQUIRE(VALID_NMSOCK(tlssock));
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(tlssock->tid == isc_nm_tid());
if (result != ISC_R_SUCCESS) {
/* Connection closed */
/* TODO accept_cb should be called if we're not initialized yet!
*/
if (tlssock->rcb.recv != NULL) {
tlssock->rcb.recv(tlssock->statichandle, result, region,
tlssock->rcbarg);
}
isc__nm_tls_close(tlssock);
return;
}
rv = BIO_write(tlssock->tls.app_bio, region->base, region->length);
INSIST(rv > 0 && (unsigned int)rv == region->length);
tls_do_bio(tlssock, TLS_CHECK_RV);
if (tlssock->tls.state != IO) {
if (SSL_is_init_finished(tlssock->tls.ssl) == 1) {
if (tlssock->server) {
tlssock->listener->accept_cb.accept(
tlssock->statichandle, ISC_R_SUCCESS,
tlssock->listener->accept_cbarg);
} else {
isc_nmhandle_t *tlshandle = isc__nmhandle_get(tlssock, NULL, NULL);
tlssock->accept_cb.connect(tlshandle, ISC_R_SUCCESS,
tlssock->accept_cbarg);
}
tlssock->tls.state = IO;
/* We need to do it again - to flush incoming buffer */
tls_do_bio(tlssock, TLS_CHECK_RV);
}
}
}
static isc_result_t
initialize_tls(isc_nmsocket_t *sock, bool srv) {
INSIST(sock->tid == isc_nm_tid());
sock->tls.ssl = SSL_new(sock->tls.ctx);
if (sock->tls.ssl == NULL) {
return (ISC_R_TLSERROR);
}
if (BIO_new_bio_pair(&(sock->tls.ssl_bio), 0, &(sock->tls.app_bio),
0) != 1) {
SSL_free(sock->tls.ssl);
return (ISC_R_TLSERROR);
}
SSL_set_bio(sock->tls.ssl, sock->tls.ssl_bio, sock->tls.ssl_bio);
if (srv) {
SSL_set_accept_state(sock->tls.ssl);
} else {
SSL_set_connect_state(sock->tls.ssl);
}
isc_nm_read(sock->outerhandle, tls_readcb, sock);
tls_do_bio(sock, TLS_CHECK_RV);
return (ISC_R_SUCCESS);
}
static isc_result_t
tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
isc_nmsocket_t *tlslistensock = (isc_nmsocket_t *)cbarg;
isc_nmsocket_t *tlssock = NULL;
REQUIRE(VALID_NMSOCK(tlslistensock));
REQUIRE(tlslistensock->type == isc_nm_tlslistener);
/* If accept() was unsuccessful we can't do anything */
if (result != ISC_R_SUCCESS) {
return (result);
}
/* We need to create a 'wrapper' tlssocket for this connection */
tlssock = isc_mem_get(handle->sock->mgr->mctx, sizeof(*tlssock));
isc__nmsocket_init(tlssock, handle->sock->mgr, isc_nm_tlssocket,
handle->sock->iface);