2014-09-09 10:19:52 -05:00
/**
*
* / brief function for stub resolving
*
*/
/*
* Copyright ( c ) 2013 , NLnet Labs , Verisign , Inc .
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* * Neither the names of the copyright holders nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL Verisign , Inc . BE LIABLE FOR ANY
* DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
* ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
* LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2015-12-18 06:40:52 -06:00
# include "config.h"
2017-04-06 04:20:08 -05:00
/* Intercept and do not sent out COM DS queries with TLS
* For debugging purposes only . Never commit with this turned on .
*/
# define INTERCEPT_COM_DS 0
2015-12-18 06:40:52 -06:00
# include "debug.h"
2015-06-12 06:51:36 -05:00
# include <openssl/err.h>
2015-09-25 11:28:45 -05:00
# include <openssl/conf.h>
2015-09-04 03:56:30 -05:00
# include <openssl/x509v3.h>
2014-10-15 16:28:59 -05:00
# include <fcntl.h>
2014-09-16 08:43:20 -05:00
# include "stub.h"
2014-10-15 16:04:39 -05:00
# include "gldns/gbuffer.h"
2014-09-16 08:43:20 -05:00
# include "gldns/pkthdr.h"
2015-04-29 13:20:25 -05:00
# include "gldns/rrdef.h"
# include "gldns/str2wire.h"
2015-11-24 11:59:01 -06:00
# include "gldns/wire2str.h"
2015-04-29 13:20:25 -05:00
# include "rr-iter.h"
2014-09-16 08:43:20 -05:00
# include "context.h"
# include "util-internal.h"
2017-10-06 06:07:15 -05:00
# include "platform.h"
2014-10-15 16:04:39 -05:00
# include "general.h"
2015-12-21 18:27:40 -06:00
# include "pubkey-pinning.h"
2018-01-10 05:47:14 -06:00
# ifdef USE_DANESSL
# include "ssl_dane / danessl.h"
# endif
2014-09-09 10:19:52 -05:00
2016-01-12 08:52:14 -06:00
/* WSA TODO:
2017-11-03 07:50:13 -05:00
* STUB_TCP_RETRY added to deal with edge triggered event loops ( versus
2016-01-12 08:52:14 -06:00
* level triggered ) . See also lines containing WSA TODO below . . .
*/
2017-03-20 09:20:17 -05:00
# define STUB_TRY_AGAIN_LATER -24 /* EMFILE, i.e. Out of OS resources */
2016-06-23 09:53:51 -05:00
# define STUB_NO_AUTH -8 /* Existing TLS connection is not authenticated */
# define STUB_CONN_GONE -7 /* Connection has failed, clear queue*/
2017-11-03 07:50:13 -05:00
# define STUB_TCP_RETRY -6
2015-10-31 05:04:56 -05:00
# define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */
2016-06-23 09:53:51 -05:00
# define STUB_SETUP_ERROR -4
2017-11-03 07:50:13 -05:00
# define STUB_TCP_MORE_TO_READ -3
# define STUB_TCP_MORE_TO_WRITE -3
2015-04-29 13:20:25 -05:00
# define STUB_TCP_ERROR -2
2015-04-27 09:32:57 -05:00
2015-05-03 09:11:46 -05:00
/* Don't currently have access to the context whilst doing handshake */
# define TIMEOUT_TLS 2500
2015-11-24 11:59:01 -06:00
/* Arbritray number of message for EDNS keepalive resend*/
# define EDNS_KEEPALIVE_RESEND 5
2015-05-03 09:11:46 -05:00
2015-03-22 10:50:48 -05:00
static time_t secret_rollover_time = 0 ;
static uint32_t secret = 0 ;
static uint32_t prev_secret = 0 ;
2015-04-19 11:16:58 -05:00
static void upstream_read_cb ( void * userarg ) ;
static void upstream_write_cb ( void * userarg ) ;
2015-06-23 09:39:56 -05:00
static void upstream_idle_timeout_cb ( void * userarg ) ;
2015-04-19 11:16:58 -05:00
static void upstream_schedule_netreq ( getdns_upstream * upstream ,
getdns_network_req * netreq ) ;
2017-10-17 06:47:29 -05:00
static void upstream_reschedule_events ( getdns_upstream * upstream ) ;
2016-06-23 09:53:51 -05:00
static int upstream_working_ok ( getdns_upstream * upstream ) ;
static int upstream_auth_status_ok ( getdns_upstream * upstream ,
getdns_network_req * netreq ) ;
2015-06-19 12:28:29 -05:00
static int upstream_connect ( getdns_upstream * upstream ,
getdns_transport_list_t transport ,
2015-06-24 12:49:34 -05:00
getdns_dns_req * dnsreq ) ;
2015-05-02 12:08:45 -05:00
static int fallback_on_write ( getdns_network_req * netreq ) ;
2015-06-23 09:39:56 -05:00
static void stub_timeout_cb ( void * userarg ) ;
2016-12-22 17:51:47 -06:00
uint64_t _getdns_get_time_as_uintt64 ( ) ;
2015-05-02 12:08:45 -05:00
/*****************************/
/* General utility functions */
/*****************************/
2015-04-19 11:16:58 -05:00
2015-03-22 10:50:48 -05:00
static void
rollover_secret ( )
{
time_t now = 0 ;
/* Create and roll server secrets */
if ( time ( & now ) < = secret_rollover_time )
return ;
/* Remember previous secret, in to keep answering on rollover
2018-02-23 16:11:46 -06:00
* boundary with old cookie .
2015-03-22 10:50:48 -05:00
*/
prev_secret = secret ;
2015-03-22 11:01:37 -05:00
secret = arc4random ( ) ;
2015-03-22 10:50:48 -05:00
/* Next rollover over EDNS_COOKIE_ROLLOVER_TIME with 30% jitter,
* I . e . some offset + or - 15 % of the future point in time .
*/
secret_rollover_time = now + ( EDNS_COOKIE_ROLLOVER_TIME / 20 * 17 )
2015-03-22 11:01:37 -05:00
+ arc4random_uniform ( EDNS_COOKIE_ROLLOVER_TIME / 10 * 3 ) ;
2015-03-22 10:50:48 -05:00
}
static void
calc_new_cookie ( getdns_upstream * upstream , uint8_t * cookie )
{
const EVP_MD * md ;
EVP_MD_CTX * mdctx ;
unsigned char md_value [ EVP_MAX_MD_SIZE ] ;
unsigned int md_len ;
size_t i ;
sa_family_t af = upstream - > addr . ss_family ;
void * sa_addr = ( ( struct sockaddr * ) & upstream - > addr ) - > sa_data ;
size_t addr_len = ( af = = AF_INET6 ? sizeof ( struct sockaddr_in6 )
: af = = AF_INET ? sizeof ( struct sockaddr_in )
: 0 ) - sizeof ( sa_family_t ) ;
md = EVP_sha256 ( ) ;
mdctx = EVP_MD_CTX_create ( ) ;
EVP_DigestInit_ex ( mdctx , md , NULL ) ;
EVP_DigestUpdate ( mdctx , & secret , sizeof ( secret ) ) ;
EVP_DigestUpdate ( mdctx , sa_addr , addr_len ) ;
EVP_DigestFinal_ex ( mdctx , md_value , & md_len ) ;
EVP_MD_CTX_destroy ( mdctx ) ;
( void ) memset ( cookie , 0 , 8 ) ;
for ( i = 0 ; i < md_len ; i + + )
cookie [ i % 8 ] ^ = md_value [ i ] ;
}
2015-10-31 22:20:12 -05:00
static getdns_return_t
attach_edns_client_subnet_private ( getdns_network_req * req )
{
2017-11-23 06:20:42 -06:00
/* see https://tools.ietf.org/html/rfc7871#section-7.1.2
* all - zeros is a request to not leak the data further :
* A two byte FAMILY field is a SHOULD even when SOURCE
* and SCOPE are 0.
* " \x00 \x02 " FAMILY : 2 for IPv6 upstreams in network byte order , or
* " \x00 \x01 " FAMILY : 1 for IPv4 upstreams in network byte order , then :
* " \x00 " SOURCE PREFIX - LENGTH : 0
* " \x00 " ; SCOPE PREFIX - LENGTH : 0
*/
return _getdns_network_req_add_upstream_option (
req , GLDNS_EDNS_CLIENT_SUBNET , 4 ,
( req - > upstream - > addr . ss_family = = AF_INET6
? " \x00 \x02 \x00 \x00 " : " \x00 \x01 \x00 \x00 " ) ) ;
2015-10-31 22:20:12 -05:00
}
2015-11-24 11:59:01 -06:00
static getdns_return_t
attach_edns_keepalive ( getdns_network_req * req )
{
/* Client always sends length 0, omits the timeout */
return _getdns_network_req_add_upstream_option ( req ,
GLDNS_EDNS_KEEPALIVE ,
0 , NULL ) ;
}
2015-10-31 05:04:56 -05:00
static getdns_return_t
attach_edns_cookie ( getdns_network_req * req )
2015-03-22 10:50:48 -05:00
{
2015-10-31 05:04:56 -05:00
getdns_upstream * upstream = req - > upstream ;
uint16_t sz ;
void * val ;
uint8_t buf [ 8 + 32 ] ; /* server cookies can be no larger than 32 bytes */
2015-03-22 10:50:48 -05:00
rollover_secret ( ) ;
if ( ! upstream - > has_client_cookie ) {
calc_new_cookie ( upstream , upstream - > client_cookie ) ;
upstream - > secret = secret ;
upstream - > has_client_cookie = 1 ;
2015-10-31 05:04:56 -05:00
sz = 8 ;
val = upstream - > client_cookie ;
2015-03-22 10:50:48 -05:00
} else if ( upstream - > secret ! = secret ) {
memcpy ( upstream - > prev_client_cookie
, upstream - > client_cookie , 8 ) ;
upstream - > has_prev_client_cookie = 1 ;
calc_new_cookie ( upstream , upstream - > client_cookie ) ;
upstream - > secret = secret ;
2015-10-31 05:04:56 -05:00
sz = 8 ;
val = upstream - > client_cookie ;
2015-03-22 10:50:48 -05:00
} else if ( ! upstream - > has_server_cookie ) {
2015-10-31 05:04:56 -05:00
sz = 8 ;
val = upstream - > client_cookie ;
2015-03-22 10:50:48 -05:00
} else {
2015-10-31 05:04:56 -05:00
sz = 8 + upstream - > server_cookie_len ;
memcpy ( buf , upstream - > client_cookie , 8 ) ;
memcpy ( buf + 8 , upstream - > server_cookie , upstream - > server_cookie_len ) ;
val = buf ;
2015-03-22 10:50:48 -05:00
}
2015-10-31 05:04:56 -05:00
return _getdns_network_req_add_upstream_option ( req , EDNS_COOKIE_OPCODE , sz , val ) ;
2015-03-22 10:50:48 -05:00
}
2016-04-13 05:06:51 -05:00
/* Will find a matching OPT RR, but leaves the caller to validate it
*
* Returns 2 when found
* 0 when not found
* and 1 on FORMERR
*/
2015-03-22 10:50:48 -05:00
static int
2015-11-24 11:59:01 -06:00
match_edns_opt_rr ( uint16_t code , uint8_t * response , size_t response_len ,
2015-12-22 04:32:15 -06:00
const uint8_t * * position , uint16_t * option_len )
2015-03-22 10:50:48 -05:00
{
2015-08-19 09:22:38 -05:00
_getdns_rr_iter rr_iter_storage , * rr_iter ;
2015-12-07 09:43:41 -06:00
const uint8_t * pos ;
2015-10-29 10:25:07 -05:00
uint16_t rdata_len , opt_code = 0 , opt_len = 0 ;
2015-03-22 10:50:48 -05:00
/* Search for the OPT RR (if any) */
2015-08-19 09:22:38 -05:00
for ( rr_iter = _getdns_rr_iter_init ( & rr_iter_storage
2015-03-22 10:50:48 -05:00
, response , response_len )
; rr_iter
2015-08-19 09:22:38 -05:00
; rr_iter = _getdns_rr_iter_next ( rr_iter ) ) {
2015-03-22 10:50:48 -05:00
2016-06-07 09:52:10 -05:00
if ( _getdns_rr_iter_section ( rr_iter ) ! = SECTION_ADDITIONAL )
2015-03-22 10:50:48 -05:00
continue ;
if ( gldns_read_uint16 ( rr_iter - > rr_type ) ! = GETDNS_RRTYPE_OPT )
continue ;
break ;
}
if ( ! rr_iter )
return 0 ; /* No OPT, no cookie */
pos = rr_iter - > rr_type + 8 ;
2015-11-24 11:59:01 -06:00
# if defined(STUB_DEBUG) && STUB_DEBUG
char str_spc [ 8192 ] , * str = str_spc ;
size_t str_len = sizeof ( str_spc ) ;
2015-12-22 04:32:15 -06:00
uint8_t * data = ( uint8_t * ) rr_iter - > pos ;
2015-11-24 11:59:01 -06:00
size_t data_len = rr_iter - > nxt - rr_iter - > pos ;
( void ) gldns_wire2str_rr_scan (
2015-12-22 04:32:15 -06:00
& data , & data_len , & str , & str_len , ( uint8_t * ) rr_iter - > pkt , rr_iter - > pkt_end - rr_iter - > pkt ) ;
2016-07-13 11:39:26 -05:00
DEBUG_STUB ( " %s %-35s: OPT RR: %s " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_READ , __FUNC__ , str_spc ) ;
2015-11-24 11:59:01 -06:00
# endif
/* OPT found, now search for the specified option */
2015-03-22 10:50:48 -05:00
if ( pos + 2 > rr_iter - > nxt )
return 1 ; /* FORMERR */
rdata_len = gldns_read_uint16 ( pos ) ; pos + = 2 ;
if ( pos + rdata_len > rr_iter - > nxt )
return 1 ; /* FORMERR */
while ( pos < rr_iter - > nxt ) {
opt_code = gldns_read_uint16 ( pos ) ; pos + = 2 ;
opt_len = gldns_read_uint16 ( pos ) ; pos + = 2 ;
if ( pos + opt_len > rr_iter - > nxt )
return 1 ; /* FORMERR */
2015-11-24 11:59:01 -06:00
if ( opt_code = = code )
2015-03-22 10:50:48 -05:00
break ;
pos + = opt_len ; /* Skip unknown options */
}
2015-11-24 11:59:01 -06:00
if ( pos > = rr_iter - > nxt | | opt_code ! = code )
2015-03-22 10:50:48 -05:00
return 0 ; /* Everything OK, just no cookie found. */
2015-11-24 11:59:01 -06:00
* position = pos ;
* option_len = opt_len ;
return 2 ;
}
2015-03-22 10:50:48 -05:00
2015-11-24 11:59:01 -06:00
/* TODO: Test combinations of EDNS0 options*/
static int
match_and_process_server_cookie (
getdns_upstream * upstream , uint8_t * response , size_t response_len )
{
2015-12-22 04:32:15 -06:00
const uint8_t * position = NULL ;
2015-11-24 11:59:01 -06:00
uint16_t option_len = 0 ;
int found = match_edns_opt_rr ( EDNS_COOKIE_OPCODE , response ,
response_len , & position , & option_len ) ;
if ( found ! = 2 )
return found ;
if ( option_len < 16 | | option_len > 40 )
2015-03-22 10:50:48 -05:00
return 1 ; /* FORMERR */
if ( ! upstream - > has_client_cookie )
return 1 ; /* Cookie reply, but we didn't sent one */
2015-11-24 11:59:01 -06:00
if ( memcmp ( upstream - > client_cookie , position , 8 ) ! = 0 ) {
2015-03-22 10:50:48 -05:00
if ( ! upstream - > has_prev_client_cookie )
return 1 ; /* Cookie didn't match */
2015-11-24 11:59:01 -06:00
if ( memcmp ( upstream - > prev_client_cookie , position , 8 ) ! = 0 )
2015-03-22 10:50:48 -05:00
return 1 ; /* Previous cookie didn't match either */
upstream - > has_server_cookie = 0 ;
return 0 ; /* Don't store server cookie, because it
* is for our previous client cookie
*/
}
2015-11-24 11:59:01 -06:00
position + = 8 ;
option_len - = 8 ;
2015-03-22 10:50:48 -05:00
upstream - > has_server_cookie = 1 ;
2015-11-24 11:59:01 -06:00
upstream - > server_cookie_len = option_len ;
( void ) memcpy ( upstream - > server_cookie , position , option_len ) ;
2015-03-22 10:50:48 -05:00
return 0 ;
}
2014-09-16 08:43:20 -05:00
2016-04-13 05:06:51 -05:00
static void
2015-11-24 11:59:01 -06:00
process_keepalive (
getdns_upstream * upstream , getdns_network_req * netreq ,
uint8_t * response , size_t response_len )
2015-04-29 13:20:25 -05:00
{
2015-12-22 04:32:15 -06:00
const uint8_t * position = NULL ;
2015-11-24 11:59:01 -06:00
uint16_t option_len = 0 ;
int found = match_edns_opt_rr ( GLDNS_EDNS_KEEPALIVE , response ,
response_len , & position , & option_len ) ;
2016-04-28 09:41:34 -05:00
if ( found ! = 2 | | option_len ! = 2 ) {
2016-07-02 10:43:47 -05:00
if ( netreq - > keepalive_sent = = 1 ) {
/* For TCP if no keepalive sent back, then we must use 0 idle timeout
as server does not support it . TLS allows idle connections without
keepalive , according to RFC7858 . */
2016-07-14 04:03:33 -05:00
# if !defined(KEEP_CONNECTIONS_OPEN_DEBUG) || !KEEP_CONNECTIONS_OPEN_DEBUG
2016-07-02 10:43:47 -05:00
if ( upstream - > transport ! = GETDNS_TRANSPORT_TLS )
upstream - > keepalive_timeout = 0 ;
else
2016-05-25 08:57:37 -05:00
# endif
2016-07-02 10:43:47 -05:00
upstream - > keepalive_timeout = netreq - > owner - > context - > idle_timeout ;
}
2016-04-13 05:06:51 -05:00
return ;
2015-04-29 13:20:25 -05:00
}
2018-01-16 09:08:22 -06:00
upstream - > server_keepalive_received = 1 ;
2015-11-24 11:59:01 -06:00
/* Use server sent value unless the client specified a shorter one.
Convert to ms first ( wire value has units of 100 ms ) */
uint64_t server_keepalive = ( ( uint64_t ) gldns_read_uint16 ( position ) ) * 100 ;
2017-06-09 04:24:51 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d Server Keepalive received: %d ms \n " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_READ , __FUNC__ , upstream - > fd ,
2016-07-21 12:24:18 -05:00
( int ) server_keepalive ) ;
2015-11-24 11:59:01 -06:00
if ( netreq - > owner - > context - > idle_timeout < server_keepalive )
upstream - > keepalive_timeout = netreq - > owner - > context - > idle_timeout ;
else {
2016-07-21 12:24:18 -05:00
if ( server_keepalive = = 0 ) {
/* This means the server wants us to shut the connection (sending no
more queries ) . */
upstream - > keepalive_shutdown = 1 ;
}
2015-11-24 11:59:01 -06:00
upstream - > keepalive_timeout = server_keepalive ;
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d Server Keepalive used: %d ms \n " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_READ , __FUNC__ , upstream - > fd ,
2016-03-01 12:05:01 -06:00
( int ) server_keepalive ) ;
2015-04-29 13:20:25 -05:00
}
}
2014-10-15 16:28:59 -05:00
/** best effort to set nonblocking */
static void
getdns_sock_nonblock ( int sockfd )
{
# ifdef HAVE_FCNTL
int flag ;
if ( ( flag = fcntl ( sockfd , F_GETFL ) ) ! = - 1 ) {
flag | = O_NONBLOCK ;
if ( fcntl ( sockfd , F_SETFL , flag ) = = - 1 ) {
/* ignore error, continue blockingly */
}
}
# elif defined(HAVE_IOCTLSOCKET)
unsigned long on = 1 ;
if ( ioctlsocket ( sockfd , FIONBIO , & on ) ! = 0 ) {
/* ignore error, continue blockingly */
}
# endif
}
2015-05-02 12:08:45 -05:00
static int
2015-06-19 12:28:29 -05:00
tcp_connect ( getdns_upstream * upstream , getdns_transport_list_t transport )
2015-05-02 12:08:45 -05:00
{
int fd = - 1 ;
2016-06-23 09:53:51 -05:00
DEBUG_STUB ( " %s %-35s: Creating TCP connection: %p \n " , STUB_DEBUG_SETUP ,
2016-12-12 07:20:31 -06:00
__FUNC__ , ( void * ) upstream ) ;
2015-05-02 12:08:45 -05:00
if ( ( fd = socket ( upstream - > addr . ss_family , SOCK_STREAM , IPPROTO_TCP ) ) = = - 1 )
return - 1 ;
getdns_sock_nonblock ( fd ) ;
2016-06-23 09:53:51 -05:00
/* Note that error detection is different with TFO. Since the handshake
doesn ' t start till the sendto ( ) lack of connection is often delayed until
then or even the subsequent event depending on the error and platform . */
2015-05-02 12:08:45 -05:00
# ifdef USE_TCP_FASTOPEN
/* Leave the connect to the later call to sendto() if using TCP*/
2015-12-17 11:20:08 -06:00
if ( transport = = GETDNS_TRANSPORT_TCP )
2015-05-02 12:08:45 -05:00
return fd ;
2015-12-13 11:44:31 -06:00
# elif USE_OSX_TCP_FASTOPEN
2016-12-08 16:25:53 -06:00
( void ) transport ;
2015-12-13 11:44:31 -06:00
sa_endpoints_t endpoints ;
endpoints . sae_srcif = 0 ;
endpoints . sae_srcaddr = NULL ;
endpoints . sae_srcaddrlen = 0 ;
endpoints . sae_dstaddr = ( struct sockaddr * ) & upstream - > addr ;
endpoints . sae_dstaddrlen = upstream - > addr_len ;
2017-08-18 11:59:49 -05:00
if ( connectx ( fd , & endpoints , SAE_ASSOCID_ANY ,
2015-12-13 11:44:31 -06:00
CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE ,
2017-08-18 11:59:49 -05:00
NULL , 0 , NULL , NULL ) = = 0 ) {
return fd ;
}
2017-11-03 07:50:13 -05:00
if ( _getdns_socketerror ( ) = = _getdns_EINPROGRESS | |
_getdns_socketerror ( ) = = _getdns_EWOULDBLOCK )
2017-08-18 11:59:49 -05:00
return fd ;
2016-12-08 16:25:53 -06:00
# else
( void ) transport ;
2015-05-02 12:08:45 -05:00
# endif
if ( connect ( fd , ( struct sockaddr * ) & upstream - > addr ,
upstream - > addr_len ) = = - 1 ) {
2017-10-04 11:31:33 -05:00
if ( _getdns_socketerror ( ) = = _getdns_EINPROGRESS | |
_getdns_socketerror ( ) = = _getdns_EWOULDBLOCK )
2016-01-12 09:54:42 -06:00
return fd ;
2017-10-04 11:31:33 -05:00
_getdns_closesocket ( fd ) ;
2016-01-12 09:54:42 -06:00
return - 1 ;
2015-05-02 12:08:45 -05:00
}
return fd ;
}
2015-06-26 08:27:21 -05:00
static int
tcp_connected ( getdns_upstream * upstream ) {
int error = 0 ;
socklen_t len = ( socklen_t ) sizeof ( error ) ;
getsockopt ( upstream - > fd , SOL_SOCKET , SO_ERROR , ( void * ) & error , & len ) ;
2017-11-03 10:26:19 -05:00
if ( _getdns_error_wants_retry ( error ) )
2017-11-03 07:50:13 -05:00
return STUB_TCP_RETRY ;
2016-06-23 09:53:51 -05:00
else if ( error ! = 0 ) {
return STUB_SETUP_ERROR ;
}
if ( upstream - > transport = = GETDNS_TRANSPORT_TCP & &
upstream - > queries_sent = = 0 ) {
upstream - > conn_state = GETDNS_CONN_OPEN ;
upstream - > conn_completed + + ;
}
2015-06-26 08:27:21 -05:00
return 0 ;
}
2015-05-02 12:08:45 -05:00
/**************************/
/* Error/cleanup functions*/
/**************************/
2014-10-15 16:04:39 -05:00
static void
2014-10-17 17:25:41 -05:00
stub_next_upstream ( getdns_network_req * netreq )
2014-10-15 16:04:39 -05:00
{
2014-10-17 17:25:41 -05:00
getdns_dns_req * dnsreq = netreq - > owner ;
2014-10-15 16:04:39 -05:00
2018-02-26 09:41:13 -06:00
if ( ! - - netreq - > upstream - > to_retry ) {
/* Limit back_off value to configured maximum */
if ( netreq - > upstream - > back_off * 2 > dnsreq - > context - > max_backoff_value )
netreq - > upstream - > to_retry = - ( dnsreq - > context - > max_backoff_value ) ;
else
netreq - > upstream - > to_retry = - ( netreq - > upstream - > back_off * = 2 ) ;
}
2014-10-16 07:24:13 -05:00
2016-06-23 09:53:51 -05:00
dnsreq - > upstreams - > current_udp + = GETDNS_UPSTREAM_TRANSPORTS ;
if ( dnsreq - > upstreams - > current_udp > = dnsreq - > upstreams - > count )
dnsreq - > upstreams - > current_udp = 0 ;
2014-10-17 17:25:41 -05:00
}
2017-10-16 07:17:49 -05:00
static void
remove_from_write_queue ( getdns_upstream * upstream , getdns_network_req * netreq )
{
getdns_network_req * r , * prev_r ;
for ( r = upstream - > write_queue , prev_r = NULL
; r
; prev_r = r , r = r - > write_queue_tail ) {
if ( r ! = netreq )
continue ;
if ( prev_r )
prev_r - > write_queue_tail = r - > write_queue_tail ;
else
upstream - > write_queue = r - > write_queue_tail ;
if ( r = = upstream - > write_queue_last ) {
/* If r was the last netreq,
* its write_queue tail MUST be NULL
*/
assert ( r - > write_queue_tail = = NULL ) ;
upstream - > write_queue_last = prev_r ? prev_r : NULL ;
}
netreq - > write_queue_tail = NULL ;
break ; /* netreq found and removed */
}
}
2014-10-17 17:25:41 -05:00
static void
stub_cleanup ( getdns_network_req * netreq )
{
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: MSG: %p \n " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_CLEANUP , __FUNC__ , ( void * ) netreq ) ;
2014-10-17 17:25:41 -05:00
getdns_dns_req * dnsreq = netreq - > owner ;
2014-10-18 07:32:55 -05:00
GETDNS_CLEAR_EVENT ( dnsreq - > loop , & netreq - > event ) ;
2014-10-16 07:24:13 -05:00
2017-10-17 06:47:29 -05:00
if ( netreq - > query_id_registered ) {
( void ) _getdns_rbtree_delete (
netreq - > query_id_registered , netreq - > node . key ) ;
netreq - > query_id_registered = NULL ;
netreq - > node . key = NULL ;
}
if ( netreq - > upstream ) {
remove_from_write_queue ( netreq - > upstream , netreq ) ;
if ( netreq - > upstream - > event . ev )
upstream_reschedule_events ( netreq - > upstream ) ;
}
2014-10-18 07:32:55 -05:00
}
static void
2016-06-23 09:53:51 -05:00
upstream_failed ( getdns_upstream * upstream , int during_setup )
2014-10-18 07:32:55 -05:00
{
2017-06-15 14:15:00 -05:00
getdns_network_req * netreq ;
2017-02-23 08:49:17 -06:00
DEBUG_STUB ( " %s %-35s: FD: %d Failure during connection setup = %d \n " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_CLEANUP , __FUNC__ , upstream - > fd , during_setup ) ;
2016-06-23 09:53:51 -05:00
/* Fallback code should take care of queue queries and then close conn
when idle . */
/* [TLS1]TODO: Work out how to re-open the connection and re-try
the queries if there is only one upstream . */
2017-10-19 07:14:37 -05:00
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
2016-06-23 09:53:51 -05:00
if ( during_setup ) {
2018-01-24 07:13:14 -06:00
upstream - > conn_setup_failed + + ;
2016-06-23 09:53:51 -05:00
} else {
upstream - > conn_shutdowns + + ;
/* [TLS1]TODO: Re-try these queries if possible.*/
2014-10-19 01:08:45 -05:00
}
2017-10-17 06:47:29 -05:00
upstream - > conn_state = GETDNS_CONN_TEARDOWN ;
2017-10-19 07:14:37 -05:00
while ( upstream - > write_queue )
upstream_write_cb ( upstream ) ;
2017-06-15 14:15:00 -05:00
while ( upstream - > netreq_by_query_id . count ) {
netreq = ( getdns_network_req * )
_getdns_rbtree_first ( & upstream - > netreq_by_query_id ) ;
stub_cleanup ( netreq ) ;
_getdns_netreq_change_state ( netreq , NET_REQ_ERRORED ) ;
_getdns_check_dns_req_complete ( netreq - > owner ) ;
}
2017-10-19 04:36:46 -05:00
_getdns_upstream_shutdown ( upstream ) ;
2014-10-17 17:25:41 -05:00
}
2015-05-02 12:08:45 -05:00
2014-10-17 17:25:41 -05:00
void
2015-08-19 09:22:38 -05:00
_getdns_cancel_stub_request ( getdns_network_req * netreq )
2014-10-17 17:25:41 -05:00
{
2016-06-23 09:53:51 -05:00
DEBUG_STUB ( " %s %-35s: MSG: %p \n " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_CLEANUP , __FUNC__ , ( void * ) netreq ) ;
2014-10-17 17:25:41 -05:00
stub_cleanup ( netreq ) ;
2016-12-05 13:38:59 -06:00
if ( netreq - > fd > = 0 ) {
2017-10-04 11:31:33 -05:00
_getdns_closesocket ( netreq - > fd ) ;
2017-07-31 16:48:09 -05:00
netreq - > fd = - 1 ;
2016-12-05 13:38:59 -06:00
}
2014-10-15 16:04:39 -05:00
}
2014-09-16 08:43:20 -05:00
2014-10-17 17:25:41 -05:00
static void
stub_timeout_cb ( void * userarg )
2014-09-16 08:43:20 -05:00
{
2014-10-15 16:04:39 -05:00
getdns_network_req * netreq = ( getdns_network_req * ) userarg ;
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: MSG: %p \n " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_CLEANUP , __FUNC__ , ( void * ) netreq ) ;
2014-10-17 17:25:41 -05:00
stub_cleanup ( netreq ) ;
2017-03-14 11:17:56 -05:00
_getdns_netreq_change_state ( netreq , NET_REQ_TIMED_OUT ) ;
2016-06-23 09:53:51 -05:00
/* Handle upstream*/
if ( netreq - > fd > = 0 ) {
2017-10-04 11:31:33 -05:00
_getdns_closesocket ( netreq - > fd ) ;
2017-07-31 16:48:09 -05:00
netreq - > fd = - 1 ;
2016-12-05 12:05:04 -06:00
netreq - > upstream - > udp_timeouts + + ;
2017-03-22 04:52:55 -05:00
if ( netreq - > upstream - > udp_timeouts % 100 = = 0 )
2017-09-12 09:01:02 -05:00
_getdns_upstream_log ( netreq - > upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_INFO ,
2018-01-24 07:13:14 -06:00
" %-40s : Upstream : UDP - Resps=%6d, Timeouts =%6d (logged every 100 responses) \n " ,
2017-06-28 14:09:40 -05:00
netreq - > upstream - > addr_str ,
2017-03-22 04:52:55 -05:00
( int ) netreq - > upstream - > udp_responses , ( int ) netreq - > upstream - > udp_timeouts ) ;
2016-06-23 09:53:51 -05:00
stub_next_upstream ( netreq ) ;
} else {
netreq - > upstream - > responses_timeouts + + ;
}
if ( netreq - > owner - > user_callback ) {
2016-06-20 11:39:15 -05:00
netreq - > debug_end_time = _getdns_get_time_as_uintt64 ( ) ;
2016-06-23 09:53:51 -05:00
/* Note this calls cancel_request which calls stub_cleanup again....!*/
2017-02-18 06:16:25 -06:00
_getdns_context_request_timed_out ( netreq - > owner ) ;
2016-06-23 07:02:55 -05:00
} else
2015-08-19 09:22:38 -05:00
_getdns_check_dns_req_complete ( netreq - > owner ) ;
2014-10-17 17:25:41 -05:00
}
2015-06-18 11:11:11 -05:00
static void
upstream_idle_timeout_cb ( void * userarg )
{
getdns_upstream * upstream = ( getdns_upstream * ) userarg ;
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d Closing connection \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_CLEANUP , __FUNC__ , upstream - > fd ) ;
2015-07-14 04:54:25 -05:00
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
2015-06-18 11:11:11 -05:00
upstream - > event . timeout_cb = NULL ;
2015-06-22 12:02:28 -05:00
upstream - > event . read_cb = NULL ;
upstream - > event . write_cb = NULL ;
2015-08-19 09:22:38 -05:00
_getdns_upstream_shutdown ( upstream ) ;
2015-06-18 11:11:11 -05:00
}
2015-05-03 09:11:46 -05:00
static void
2016-06-23 09:53:51 -05:00
upstream_setup_timeout_cb ( void * userarg )
2015-05-03 09:11:46 -05:00
{
getdns_upstream * upstream = ( getdns_upstream * ) userarg ;
2017-03-20 17:17:44 -05:00
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_CLEANUP , __FUNC__ , upstream - > fd ) ;
2015-05-03 09:11:46 -05:00
2017-10-17 06:47:29 -05:00
upstream_failed ( upstream , 1 ) ;
2015-05-03 09:11:46 -05:00
}
2015-06-23 09:39:56 -05:00
2015-05-02 12:08:45 -05:00
/****************************/
/* TCP read/write functions */
/****************************/
2014-10-16 07:24:13 -05:00
2014-10-17 17:25:41 -05:00
static int
2016-01-12 08:52:14 -06:00
stub_tcp_read ( int fd , getdns_tcp_state * tcp , struct mem_funcs * mf )
2014-10-17 17:25:41 -05:00
{
2014-10-24 16:12:28 -05:00
ssize_t read ;
2014-10-17 17:25:41 -05:00
uint8_t * buf ;
size_t buf_size ;
if ( ! tcp - > read_buf ) {
/* First time tcp read, create a buffer for reading */
if ( ! ( tcp - > read_buf = GETDNS_XMALLOC ( * mf , uint8_t , 4096 ) ) )
return STUB_TCP_ERROR ;
tcp - > read_buf_len = 4096 ;
tcp - > read_pos = tcp - > read_buf ;
tcp - > to_read = 2 ; /* Packet size */
}
2015-12-24 07:41:50 -06:00
read = recv ( fd , ( void * ) tcp - > read_pos , tcp - > to_read , 0 ) ;
2016-12-08 07:05:58 -06:00
if ( read < 0 ) {
2017-11-03 10:42:38 -05:00
if ( _getdns_socketerror_wants_retry ( ) )
2017-11-03 07:50:13 -05:00
return STUB_TCP_RETRY ;
2014-10-17 17:25:41 -05:00
else
return STUB_TCP_ERROR ;
2014-10-18 07:32:55 -05:00
} else if ( read = = 0 ) {
/* Remote end closed the socket */
/* TODO: Try to reconnect */
return STUB_TCP_ERROR ;
2016-12-08 07:05:58 -06:00
} else if ( ( size_t ) read > tcp - > to_read ) {
2016-01-12 08:52:14 -06:00
return STUB_TCP_ERROR ;
2014-10-17 17:25:41 -05:00
}
tcp - > to_read - = read ;
tcp - > read_pos + = read ;
2016-01-12 08:52:14 -06:00
if ( tcp - > to_read > 0 )
2017-11-03 07:50:13 -05:00
return STUB_TCP_MORE_TO_READ ;
2014-10-17 17:25:41 -05:00
read = tcp - > read_pos - tcp - > read_buf ;
if ( read = = 2 ) {
/* Read the packet size short */
tcp - > to_read = gldns_read_uint16 ( tcp - > read_buf ) ;
if ( tcp - > to_read < GLDNS_HEADER_SIZE )
return STUB_TCP_ERROR ;
/* Resize our buffer if needed */
if ( tcp - > to_read > tcp - > read_buf_len ) {
buf_size = tcp - > read_buf_len ;
while ( tcp - > to_read > buf_size )
buf_size * = 2 ;
if ( ! ( buf = GETDNS_XREALLOC ( * mf ,
2015-02-12 05:05:10 -06:00
tcp - > read_buf , uint8_t , buf_size ) ) )
2014-10-17 17:25:41 -05:00
return STUB_TCP_ERROR ;
tcp - > read_buf = buf ;
tcp - > read_buf_len = buf_size ;
}
/* Ready to start reading the packet */
tcp - > read_pos = tcp - > read_buf ;
2017-11-03 07:50:13 -05:00
return STUB_TCP_MORE_TO_READ ;
2014-10-17 17:25:41 -05:00
}
return GLDNS_ID_WIRE ( tcp - > read_buf ) ;
}
2015-05-02 12:08:45 -05:00
/* stub_tcp_write(fd, tcp, netreq)
2017-11-03 07:50:13 -05:00
* will return STUB_TCP_RETRY or STUB_TCP_MORE_TO_WRITE when we need to come
* back again , STUB_TCP_ERROR on error and a query_id on successful sent .
2015-05-02 12:08:45 -05:00
*/
static int
stub_tcp_write ( int fd , getdns_tcp_state * tcp , getdns_network_req * netreq )
2014-10-17 17:25:41 -05:00
{
2015-10-31 05:04:56 -05:00
size_t pkt_len ;
2015-05-02 12:08:45 -05:00
ssize_t written ;
uint16_t query_id ;
intptr_t query_id_intptr ;
2014-10-17 17:25:41 -05:00
2015-06-26 08:27:21 -05:00
int q = tcp_connected ( netreq - > upstream ) ;
if ( q ! = 0 )
return q ;
2015-06-24 12:49:34 -05:00
2015-11-13 07:28:43 -06:00
netreq - > debug_udp = 0 ;
2015-05-02 12:08:45 -05:00
/* Do we have remaining data that we could not write before? */
if ( ! tcp - > write_buf ) {
/* No, this is an initial write. Try to send
*/
2016-01-12 08:52:14 -06:00
do {
2015-05-02 12:08:45 -05:00
query_id = arc4random ( ) ;
query_id_intptr = ( intptr_t ) query_id ;
netreq - > node . key = ( void * ) query_id_intptr ;
2014-10-17 17:25:41 -05:00
2015-08-19 09:07:01 -05:00
} while ( ! _getdns_rbtree_insert (
2015-05-02 12:08:45 -05:00
& netreq - > upstream - > netreq_by_query_id , & netreq - > node ) ) ;
2017-10-17 06:47:29 -05:00
netreq - > query_id_registered = & netreq - > upstream - > netreq_by_query_id ;
2014-10-17 17:25:41 -05:00
2015-05-02 12:08:45 -05:00
GLDNS_ID_SET ( netreq - > query , query_id ) ;
2017-06-15 10:21:05 -05:00
2015-05-02 12:08:45 -05:00
if ( netreq - > opt ) {
2015-10-31 05:04:56 -05:00
_getdns_network_req_clear_upstream_options ( netreq ) ;
2015-05-02 12:08:45 -05:00
/* no limits on the max udp payload size with tcp */
gldns_write_uint16 ( netreq - > opt + 3 , 65535 ) ;
2015-10-31 05:04:56 -05:00
if ( netreq - > owner - > edns_cookies )
if ( attach_edns_cookie ( netreq ) )
return STUB_OUT_OF_OPTIONS ;
2015-10-31 22:20:12 -05:00
if ( netreq - > owner - > edns_client_subnet_private )
if ( attach_edns_client_subnet_private ( netreq ) )
return STUB_OUT_OF_OPTIONS ;
2016-06-23 09:53:51 -05:00
if ( netreq - > upstream - > queries_sent = = 0 & &
2015-11-24 11:59:01 -06:00
netreq - > owner - > context - > idle_timeout ! = 0 ) {
/* Add the keepalive option to the first query on this connection*/
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d Requesting keepalive \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_WRITE , __FUNC__ , fd ) ;
2015-11-24 11:59:01 -06:00
if ( attach_edns_keepalive ( netreq ) )
return STUB_OUT_OF_OPTIONS ;
netreq - > keepalive_sent = 1 ;
}
2015-05-02 12:08:45 -05:00
}
2015-12-21 15:11:16 -06:00
pkt_len = _getdns_network_req_add_tsig ( netreq ) ;
2015-05-02 12:08:45 -05:00
/* We have an initialized packet buffer.
* Lets see how much of it we can write
*/
/* We use sendto() here which will do both a connect and send */
2016-01-12 08:52:14 -06:00
# ifdef USE_TCP_FASTOPEN
2015-05-02 12:08:45 -05:00
written = sendto ( fd , netreq - > query - 2 , pkt_len + 2 ,
MSG_FASTOPEN , ( struct sockaddr * ) & ( netreq - > upstream - > addr ) ,
netreq - > upstream - > addr_len ) ;
/* If pipelining we will find that the connection is already up so
just fall back to a ' normal ' write . */
2017-11-03 07:50:13 -05:00
if ( written = = - 1 & & _getdns_socketerror ( ) = = _getdns_EISCONN )
2015-05-02 12:08:45 -05:00
written = write ( fd , netreq - > query - 2 , pkt_len + 2 ) ;
2015-12-17 05:37:33 -06:00
# else
2015-12-24 07:41:50 -06:00
written = sendto ( fd , ( const char * ) ( netreq - > query - 2 ) ,
pkt_len + 2 , 0 ,
( struct sockaddr * ) & ( netreq - > upstream - > addr ) ,
netreq - > upstream - > addr_len ) ;
2015-12-17 05:37:33 -06:00
# endif
2017-11-03 10:42:38 -05:00
if ( ( written = = - 1 & & _getdns_socketerror_wants_retry ( ) ) | |
2017-11-03 07:50:13 -05:00
( size_t ) written < pkt_len + 2 ) {
2016-01-12 08:52:14 -06:00
2015-05-02 12:08:45 -05:00
/* We couldn't write the whole packet.
* Setup tcp to track the state .
*/
tcp - > write_buf = netreq - > query - 2 ;
tcp - > write_buf_len = pkt_len + 2 ;
tcp - > written = written > = 0 ? written : 0 ;
2017-11-03 07:50:13 -05:00
return written = = - 1
? STUB_TCP_RETRY
: STUB_TCP_MORE_TO_WRITE ;
2015-05-02 12:08:45 -05:00
2017-06-14 08:36:53 -05:00
} else if ( written = = - 1 ) {
DEBUG_STUB ( " %s %-35s: MSG: %p error while writing to TCP socket: "
" %s \n " , STUB_DEBUG_WRITE , __FUNC__ , ( void * ) netreq
2017-11-03 07:50:13 -05:00
, _getdns_errnostr ( ) ) ;
2017-06-14 08:36:53 -05:00
2015-05-02 12:08:45 -05:00
return STUB_TCP_ERROR ;
2017-06-14 08:36:53 -05:00
}
2015-05-02 12:08:45 -05:00
/* We were able to write everything! Start reading. */
return ( int ) query_id ;
} else { /* if (! tcp->write_buf) */
/* Coming back from an earlier unfinished write or handshake.
* Try to send remaining data */
2017-09-21 04:03:38 -05:00
written = send ( fd , ( void * ) ( tcp - > write_buf + tcp - > written ) ,
2016-12-05 13:38:59 -06:00
tcp - > write_buf_len - tcp - > written , 0 ) ;
2015-05-02 12:08:45 -05:00
if ( written = = - 1 ) {
2017-11-03 10:42:38 -05:00
if ( _getdns_socketerror_wants_retry ( ) )
2017-11-03 07:50:13 -05:00
return STUB_TCP_RETRY ;
2017-06-14 08:36:53 -05:00
else {
DEBUG_STUB ( " %s %-35s: MSG: %p error while writing to TCP socket: "
" %s \n " , STUB_DEBUG_WRITE , __FUNC__ , ( void * ) netreq
2017-11-03 07:50:13 -05:00
, _getdns_errnostr ( ) ) ;
2017-06-14 08:36:53 -05:00
2015-05-02 12:08:45 -05:00
return STUB_TCP_ERROR ;
2017-06-14 08:36:53 -05:00
}
2015-05-02 12:08:45 -05:00
}
tcp - > written + = written ;
if ( tcp - > written < tcp - > write_buf_len )
/* Still more to send */
2017-11-03 07:50:13 -05:00
return STUB_TCP_MORE_TO_WRITE ;
2015-05-02 12:08:45 -05:00
query_id = ( int ) GLDNS_ID_WIRE ( tcp - > write_buf + 2 ) ;
/* Done. Start reading */
tcp - > write_buf = NULL ;
return query_id ;
} /* if (! tcp->write_buf) */
}
/*************************/
/* TLS Utility functions */
/*************************/
static int
tls_requested ( getdns_network_req * netreq )
{
2015-06-19 12:28:29 -05:00
return ( netreq - > transports [ netreq - > transport_current ] = =
2015-12-17 11:20:08 -06:00
GETDNS_TRANSPORT_TLS ) ?
2015-05-02 12:08:45 -05:00
1 : 0 ;
}
2018-01-04 08:58:09 -06:00
2018-01-10 05:47:14 -06:00
# if defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL)
2018-01-04 08:58:09 -06:00
static int
2018-01-10 05:47:14 -06:00
_getdns_tls_verify_always_ok ( int ok , X509_STORE_CTX * ctx )
{
# if defined(STUB_DEBUG) && STUB_DEBUG
char buf [ 8192 ] ;
X509 * cert ;
int err ;
int depth ;
cert = X509_STORE_CTX_get_current_cert ( ctx ) ;
err = X509_STORE_CTX_get_error ( ctx ) ;
depth = X509_STORE_CTX_get_error_depth ( ctx ) ;
if ( cert )
X509_NAME_oneline ( X509_get_subject_name ( cert ) , buf , sizeof ( buf ) ) ;
else
strcpy ( buf , " <unknown> " ) ;
DEBUG_STUB ( " DEBUG Cert verify: depth=%d verify=%d err=%d subject=%s errorstr=%s \n " , depth , ok , err , buf , X509_verify_cert_error_string ( err ) ) ;
# else /* defined(STUB_DEBUG) && STUB_DEBUG */
( void ) ok ;
( void ) ctx ;
# endif /* #else defined(STUB_DEBUG) && STUB_DEBUG */
return 1 ;
}
2018-01-04 08:58:09 -06:00
2018-01-10 05:47:14 -06:00
# else /* defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) */
2018-01-04 08:58:09 -06:00
static int
2015-10-21 09:01:40 -05:00
tls_verify_callback ( int preverify_ok , X509_STORE_CTX * ctx )
{
2015-12-21 18:27:40 -06:00
getdns_upstream * upstream ;
2015-12-21 20:23:13 -06:00
getdns_return_t pinset_ret = GETDNS_RETURN_GOOD ;
2016-03-01 12:05:01 -06:00
upstream = _getdns_upstream_from_x509_store ( ctx ) ;
2016-11-09 10:41:40 -06:00
if ( ! upstream )
return 0 ;
2015-12-31 04:26:29 -06:00
2016-12-07 11:01:03 -06:00
int err = X509_STORE_CTX_get_error ( ctx ) ;
2018-01-04 08:58:09 -06:00
# if defined(STUB_DEBUG) && STUB_DEBUG
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d Verify result: (%d) \" %s \" \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ , upstream - > fd , err ,
2016-03-01 12:05:01 -06:00
X509_verify_cert_error_string ( err ) ) ;
2018-01-04 08:58:09 -06:00
# endif
2017-02-23 10:48:16 -06:00
if ( ! preverify_ok & & ! upstream - > tls_fallback_ok )
2017-09-12 09:01:02 -05:00
_getdns_upstream_log ( upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_ERR ,
2018-01-24 07:13:14 -06:00
" %-40s : Verify failed: TLS - *Failure* - (%d) \" %s \" \n " ,
2017-06-28 14:09:40 -05:00
upstream - > addr_str , err ,
2017-06-26 17:23:22 -05:00
X509_verify_cert_error_string ( err ) ) ;
2015-09-25 11:28:45 -05:00
2018-01-10 05:47:14 -06:00
/* No need to deal with hostname authentication, since this will be
* dealt with in the DANE preprocessor paths .
*/
2016-12-07 11:01:03 -06:00
2018-01-10 05:47:14 -06:00
/* Deal with the pinset validation */
2016-11-09 10:41:40 -06:00
if ( upstream - > tls_pubkey_pinset )
2015-12-21 20:23:13 -06:00
pinset_ret = _getdns_verify_pinset_match ( upstream - > tls_pubkey_pinset , ctx ) ;
if ( pinset_ret ! = GETDNS_RETURN_GOOD ) {
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d, WARNING: Pinset validation failure! \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ , upstream - > fd ) ;
2015-12-21 20:23:13 -06:00
preverify_ok = 0 ;
2016-06-23 09:53:51 -05:00
upstream - > tls_auth_state = GETDNS_AUTH_FAILED ;
2015-12-21 20:23:13 -06:00
if ( upstream - > tls_fallback_ok )
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d, WARNING: Proceeding even though pinset validation failed! \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ , upstream - > fd ) ;
2017-02-23 09:38:45 -06:00
else
2017-09-12 09:01:02 -05:00
_getdns_upstream_log ( upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_ERR ,
2018-01-24 07:13:14 -06:00
" %-40s : Conn failed: TLS - *Failure* - Pinset validation failure \n " ,
2017-06-28 14:09:40 -05:00
upstream - > addr_str ) ;
2015-12-21 20:23:13 -06:00
}
2018-02-23 16:11:46 -06:00
/* If nothing has failed yet and we had credentials, we have successfully authenticated*/
2016-12-07 11:01:03 -06:00
if ( preverify_ok = = 0 )
upstream - > tls_auth_state = GETDNS_AUTH_FAILED ;
else if ( upstream - > tls_auth_state = = GETDNS_AUTH_NONE & &
( upstream - > tls_pubkey_pinset | | upstream - > tls_auth_name [ 0 ] ) )
2016-06-23 09:53:51 -05:00
upstream - > tls_auth_state = GETDNS_AUTH_OK ;
2017-02-23 09:38:45 -06:00
2015-12-22 09:12:25 -06:00
/* If fallback is allowed, proceed regardless of what the auth error is
( might not be hostname or pinset related ) */
2016-11-09 10:41:40 -06:00
return ( upstream - > tls_fallback_ok ) ? 1 : preverify_ok ;
2015-09-25 11:28:45 -05:00
}
2018-01-10 05:47:14 -06:00
# endif /* #else defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) */
2018-01-04 08:58:09 -06:00
2015-04-17 09:50:08 -05:00
static SSL *
2015-09-25 11:28:45 -05:00
tls_create_object ( getdns_dns_req * dnsreq , int fd , getdns_upstream * upstream )
2014-12-07 13:03:34 -06:00
{
/* Create SSL instance */
2015-09-25 11:28:45 -05:00
getdns_context * context = dnsreq - > context ;
2015-09-21 07:02:03 -05:00
if ( context - > tls_ctx = = NULL )
2015-04-17 12:38:13 -05:00
return NULL ;
2015-04-19 11:16:58 -05:00
SSL * ssl = SSL_new ( context - > tls_ctx ) ;
2015-04-30 06:24:13 -05:00
if ( ! ssl )
2014-12-07 13:03:34 -06:00
return NULL ;
/* Connect the SSL object with a file descriptor */
2015-04-19 11:16:58 -05:00
if ( ! SSL_set_fd ( ssl , fd ) ) {
2014-12-07 13:03:34 -06:00
SSL_free ( ssl ) ;
return NULL ;
}
2018-02-12 08:40:17 -06:00
# if defined(HAVE_DECL_SSL_SET1_CURVES_LIST) && HAVE_DECL_SSL_SET1_CURVES_LIST
if ( upstream - > tls_curves_list )
( void ) SSL_set1_curves_list ( ssl , upstream - > tls_curves_list ) ;
# endif
2015-12-21 18:27:40 -06:00
/* make sure we'll be able to find the context again when we need it */
if ( _getdns_associate_upstream_with_SSL ( ssl , upstream ) ! = GETDNS_RETURN_GOOD ) {
SSL_free ( ssl ) ;
return NULL ;
}
2015-09-25 11:28:45 -05:00
/* NOTE: this code will fallback on a given upstream, without trying
2015-10-16 10:56:39 -05:00
authentication on other upstreams first . This is non - optimal and but avoids
multiple TLS handshakes before getting a usable connection . */
2015-09-25 11:28:45 -05:00
2015-12-21 18:27:40 -06:00
upstream - > tls_fallback_ok = 0 ;
2015-10-16 10:56:39 -05:00
/* If we have a hostname, always use it */
if ( upstream - > tls_auth_name [ 0 ] ! = ' \0 ' ) {
2015-09-25 11:28:45 -05:00
/*Request certificate for the auth_name*/
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: Hostname verification requested for: %s \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ , upstream - > tls_auth_name ) ;
2015-09-25 11:28:45 -05:00
SSL_set_tlsext_host_name ( ssl , upstream - > tls_auth_name ) ;
2018-02-09 08:18:44 -06:00
# if defined(HAVE_SSL_HN_AUTH)
2018-01-10 05:47:14 -06:00
/* Set up native OpenSSL hostname verification
* ( doesn ' t work with USE_DANESSL , but we verify the
* name afterwards in such cases )
*/
2015-09-25 11:28:45 -05:00
X509_VERIFY_PARAM * param ;
param = SSL_get0_param ( ssl ) ;
X509_VERIFY_PARAM_set_hostflags ( param , X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS ) ;
X509_VERIFY_PARAM_set1_host ( param , upstream - > tls_auth_name , 0 ) ;
2018-02-09 08:18:44 -06:00
# elif !defined(HAVE_X509_CHECK_HOST)
2015-12-22 14:39:22 -06:00
if ( dnsreq - > netreqs [ 0 ] - > tls_auth_min = = GETDNS_AUTHENTICATION_REQUIRED ) {
2017-10-19 04:36:46 -05:00
DEBUG_STUB ( " %s %-35s: ERROR: Hostname Authentication not available from TLS library (check library version) \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ ) ;
2017-10-19 04:36:46 -05:00
_getdns_upstream_log ( upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_ERR ,
" %-40s : ERROR: Hostname Authentication not available from TLS library (check library version) \n " ,
upstream - > addr_str ) ;
2015-09-25 11:28:45 -05:00
upstream - > tls_hs_state = GETDNS_HS_FAILED ;
2018-01-30 05:23:23 -06:00
SSL_free ( ssl ) ;
2018-01-24 07:13:14 -06:00
upstream - > tls_auth_state = GETDNS_AUTH_FAILED ;
2015-09-25 11:28:45 -05:00
return NULL ;
}
# endif
2015-10-30 02:17:18 -05:00
/* Allow fallback to opportunistic if settings permit it*/
2015-12-22 14:39:22 -06:00
if ( dnsreq - > netreqs [ 0 ] - > tls_auth_min ! = GETDNS_AUTHENTICATION_REQUIRED )
2015-12-21 18:27:40 -06:00
upstream - > tls_fallback_ok = 1 ;
2015-10-16 10:56:39 -05:00
} else {
2015-12-22 15:13:14 -06:00
/* Lack of host name is OK unless only authenticated
* TLS is specified and we have no pubkey_pinset */
2015-12-22 14:39:22 -06:00
if ( dnsreq - > netreqs [ 0 ] - > tls_auth_min = = GETDNS_AUTHENTICATION_REQUIRED ) {
2015-12-22 15:13:14 -06:00
if ( upstream - > tls_pubkey_pinset ) {
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: Proceeding with only pubkey pinning authentication \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ ) ;
2015-12-22 15:13:14 -06:00
} else {
2018-01-24 07:13:14 -06:00
DEBUG_STUB ( " %s %-35s: ERROR:No auth name or pinset provided for this upstream for Strict TLS authentication \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ ) ;
2018-01-24 07:13:14 -06:00
_getdns_upstream_log ( upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_ERR ,
" %-40s : Verify fail: *CONFIG ERROR* - No auth name or pinset provided for this upstream for Strict TLS authentication \n " ,
upstream - > addr_str ) ;
2015-12-22 15:13:14 -06:00
upstream - > tls_hs_state = GETDNS_HS_FAILED ;
2018-01-30 05:23:23 -06:00
SSL_free ( ssl ) ;
2018-01-24 07:13:14 -06:00
upstream - > tls_auth_state = GETDNS_AUTH_FAILED ;
2015-12-22 15:13:14 -06:00
return NULL ;
}
2015-10-16 10:56:39 -05:00
} else {
2015-12-22 09:12:25 -06:00
/* no hostname verification, so we will make opportunistic connections */
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: Proceeding even though no hostname provided! \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ ) ;
2015-12-21 18:27:40 -06:00
upstream - > tls_fallback_ok = 1 ;
2015-10-16 10:56:39 -05:00
}
2015-09-25 11:28:45 -05:00
}
2015-12-22 09:12:25 -06:00
if ( upstream - > tls_fallback_ok ) {
2015-12-21 18:27:40 -06:00
SSL_set_cipher_list ( ssl , " DEFAULT " ) ;
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: WARNING: Using Oppotunistic TLS (fallback allowed)! \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ ) ;
2017-12-21 05:30:15 -06:00
} else {
if ( upstream - > tls_cipher_list )
SSL_set_cipher_list ( ssl , upstream - > tls_cipher_list ) ;
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: Using Strict TLS \n " , STUB_DEBUG_SETUP_TLS ,
2016-12-12 06:55:10 -06:00
__FUNC__ ) ;
2017-12-21 05:30:15 -06:00
}
2018-01-10 05:47:14 -06:00
# if defined(HAVE_SSL_DANE_ENABLE)
2018-01-10 06:54:18 -06:00
int osr ;
# if defined(STUB_DEBUG) && STUB_DEBUG
osr =
# else
( void )
# endif
SSL_dane_enable ( ssl , * upstream - > tls_auth_name ? upstream - > tls_auth_name : NULL ) ;
2018-01-04 08:58:09 -06:00
DEBUG_STUB ( " %s %-35s: DEBUG: SSL_dane_enable( \" %s \" ) -> %d \n "
, STUB_DEBUG_SETUP_TLS , __FUNC__ , upstream - > tls_auth_name , osr ) ;
SSL_set_verify ( ssl , SSL_VERIFY_PEER , _getdns_tls_verify_always_ok ) ;
sha256_pin_t * pin_p ;
size_t n_pins = 0 ;
for ( pin_p = upstream - > tls_pubkey_pinset ; pin_p ; pin_p = pin_p - > next ) {
osr = SSL_dane_tlsa_add ( ssl , 2 , 1 , 1 ,
( unsigned char * ) pin_p - > pin , SHA256_DIGEST_LENGTH ) ;
DEBUG_STUB ( " %s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d \n "
, STUB_DEBUG_SETUP_TLS , __FUNC__ , osr ) ;
if ( osr > 0 )
+ + n_pins ;
osr = SSL_dane_tlsa_add ( ssl , 3 , 1 , 1 ,
( unsigned char * ) pin_p - > pin , SHA256_DIGEST_LENGTH ) ;
DEBUG_STUB ( " %s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d \n "
, STUB_DEBUG_SETUP_TLS , __FUNC__ , osr ) ;
if ( osr > 0 )
+ + n_pins ;
}
2018-01-10 05:47:14 -06:00
# elif defined(USE_DANESSL)
if ( upstream - > tls_pubkey_pinset ) {
const char * auth_names [ 2 ] = { upstream - > tls_auth_name , NULL } ;
2018-01-10 06:54:18 -06:00
int osr ;
# if defined(STUB_DEBUG) && STUB_DEBUG
osr =
# else
( void )
# endif
DANESSL_init ( ssl ,
2018-01-10 05:47:14 -06:00
* upstream - > tls_auth_name ? upstream - > tls_auth_name : NULL ,
* upstream - > tls_auth_name ? auth_names : NULL
) ;
DEBUG_STUB ( " %s %-35s: DEBUG: DANESSL_init( \" %s \" ) -> %d \n "
, STUB_DEBUG_SETUP_TLS , __FUNC__ , upstream - > tls_auth_name , osr ) ;
SSL_set_verify ( ssl , SSL_VERIFY_PEER , _getdns_tls_verify_always_ok ) ;
sha256_pin_t * pin_p ;
size_t n_pins = 0 ;
for ( pin_p = upstream - > tls_pubkey_pinset ; pin_p ; pin_p = pin_p - > next ) {
osr = DANESSL_add_tlsa ( ssl , 3 , 1 , " sha256 " ,
( unsigned char * ) pin_p - > pin , SHA256_DIGEST_LENGTH ) ;
DEBUG_STUB ( " %s %-35s: DEBUG: DANESSL_add_tlsa() -> %d \n "
, STUB_DEBUG_SETUP_TLS , __FUNC__ , osr ) ;
if ( osr > 0 )
+ + n_pins ;
osr = DANESSL_add_tlsa ( ssl , 2 , 1 , " sha256 " ,
( unsigned char * ) pin_p - > pin , SHA256_DIGEST_LENGTH ) ;
DEBUG_STUB ( " %s %-35s: DEBUG: DANESSL_add_tlsa() -> %d \n "
, STUB_DEBUG_SETUP_TLS , __FUNC__ , osr ) ;
if ( osr > 0 )
+ + n_pins ;
}
} else {
SSL_set_verify ( ssl , SSL_VERIFY_PEER , _getdns_tls_verify_always_ok ) ;
}
2018-01-04 08:58:09 -06:00
# else
2015-12-21 18:27:40 -06:00
SSL_set_verify ( ssl , SSL_VERIFY_PEER , tls_verify_callback ) ;
2018-01-04 08:58:09 -06:00
# endif
2015-12-22 09:12:25 -06:00
2014-12-07 13:03:34 -06:00
SSL_set_connect_state ( ssl ) ;
( void ) SSL_set_mode ( ssl , SSL_MODE_AUTO_RETRY ) ;
2016-10-21 08:18:24 -05:00
/* Session resumption. There are trade-offs here. Want to do it when
possible only if we have the right type of connection . Note a change
to the upstream auth info creates a new upstream so never re - uses . */
if ( upstream - > tls_session ! = NULL ) {
if ( ( upstream - > tls_fallback_ok = = 0 & &
upstream - > last_tls_auth_state = = GETDNS_AUTH_OK ) | |
upstream - > tls_fallback_ok = = 1 ) {
SSL_set_session ( ssl , upstream - > tls_session ) ;
DEBUG_STUB ( " %s %-35s: Attempting session re-use \n " , STUB_DEBUG_SETUP_TLS ,
2016-12-12 07:20:31 -06:00
__FUNC__ ) ;
2016-10-21 08:18:24 -05:00
}
}
2015-04-19 11:16:58 -05:00
return ssl ;
2015-09-21 07:02:03 -05:00
}
2015-04-19 11:16:58 -05:00
static int
2015-05-03 09:11:46 -05:00
tls_do_handshake ( getdns_upstream * upstream )
2015-04-19 11:16:58 -05:00
{
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d \n " , STUB_DEBUG_SETUP_TLS ,
2016-12-12 06:55:10 -06:00
__FUNC__ , upstream - > fd ) ;
2014-12-07 13:03:34 -06:00
int r ;
int want ;
2015-04-19 11:16:58 -05:00
ERR_clear_error ( ) ;
while ( ( r = SSL_do_handshake ( upstream - > tls_obj ) ) ! = 1 )
2014-12-07 13:03:34 -06:00
{
2015-04-19 11:16:58 -05:00
want = SSL_get_error ( upstream - > tls_obj , r ) ;
2014-12-07 13:03:34 -06:00
switch ( want ) {
case SSL_ERROR_WANT_READ :
2015-07-14 04:54:25 -05:00
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
2015-04-19 11:16:58 -05:00
upstream - > event . read_cb = upstream_read_cb ;
upstream - > event . write_cb = NULL ;
GETDNS_SCHEDULE_EVENT ( upstream - > loop ,
2015-05-03 09:11:46 -05:00
upstream - > fd , TIMEOUT_TLS , & upstream - > event ) ;
2015-04-19 11:16:58 -05:00
upstream - > tls_hs_state = GETDNS_HS_READ ;
2017-11-03 07:50:13 -05:00
return STUB_TCP_RETRY ;
2014-12-07 13:03:34 -06:00
case SSL_ERROR_WANT_WRITE :
2015-07-14 04:54:25 -05:00
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
2015-04-19 11:16:58 -05:00
upstream - > event . read_cb = NULL ;
upstream - > event . write_cb = upstream_write_cb ;
GETDNS_SCHEDULE_EVENT ( upstream - > loop ,
2015-05-03 09:11:46 -05:00
upstream - > fd , TIMEOUT_TLS , & upstream - > event ) ;
2015-04-19 11:16:58 -05:00
upstream - > tls_hs_state = GETDNS_HS_WRITE ;
2017-11-03 07:50:13 -05:00
return STUB_TCP_RETRY ;
2015-05-03 09:11:46 -05:00
default :
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d Handshake failed %d \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ , upstream - > fd ,
2016-03-01 12:05:01 -06:00
want ) ;
2016-06-23 09:53:51 -05:00
return STUB_SETUP_ERROR ;
2014-12-07 13:03:34 -06:00
}
}
2016-10-21 08:18:24 -05:00
/* A re-used session is not verified so need to fix up state in that case */
if ( SSL_session_reused ( upstream - > tls_obj ) )
upstream - > tls_auth_state = upstream - > last_tls_auth_state ;
2018-01-04 08:58:09 -06:00
else if ( upstream - > tls_pubkey_pinset | | upstream - > tls_auth_name [ 0 ] ) {
X509 * peer_cert = SSL_get_peer_certificate ( upstream - > tls_obj ) ;
long verify_result = SSL_get_verify_result ( upstream - > tls_obj ) ;
2018-01-10 05:47:14 -06:00
/* In case of DANESSL use, and a tls_auth_name was given alongside a pinset,
* we need to verify auth_name explicitely ( otherwise it will not be checked ,
* because this is not required with DANE with an EE match ) .
* This is not needed with native OpenSSL DANE , because EE name checks have
* to be disabled explicitely .
*/
2018-02-12 08:46:42 -06:00
# if defined(HAVE_X509_CHECK_HOST) && (defined(USE_DANESSL) || !defined(HAVE_SSL_HN_AUTH))
2018-02-09 08:18:44 -06:00
int xch ;
2018-01-10 05:47:14 -06:00
if ( peer_cert & & verify_result = = X509_V_OK
& & upstream - > tls_auth_name [ 0 ]
2018-02-08 07:04:02 -06:00
& & ( xch = X509_check_host ( peer_cert ,
upstream - > tls_auth_name ,
strlen ( upstream - > tls_auth_name ) ,
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS ,
NULL ) ) < = 0 )
verify_result = X509_V_ERR_HOSTNAME_MISMATCH ;
# endif
2018-01-04 08:58:09 -06:00
upstream - > tls_auth_state = peer_cert & & verify_result = = X509_V_OK
? GETDNS_AUTH_OK : GETDNS_AUTH_FAILED ;
if ( ! peer_cert )
_getdns_upstream_log ( upstream ,
GETDNS_LOG_UPSTREAM_STATS ,
( upstream - > tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR ) ,
2018-02-07 10:08:55 -06:00
" %-40s : Verify failed : TLS - %s - "
2018-01-04 08:58:09 -06:00
" Remote did not offer certificate \n " ,
upstream - > addr_str ,
( upstream - > tls_fallback_ok
2018-01-10 05:47:14 -06:00
? " Tolerated because of Opportunistic profile "
2018-01-04 08:58:09 -06:00
: " *Failure* " ) ) ;
2018-02-07 07:38:31 -06:00
/* Since we don't have DANE validation yet, DANE validation
* failures are always pinset validation failures
*/
2018-02-08 07:04:02 -06:00
# if defined(HAVE_SSL_DANE_ENABLE)
2018-02-07 07:38:31 -06:00
else if ( verify_result = = X509_V_ERR_DANE_NO_MATCH )
_getdns_upstream_log ( upstream ,
GETDNS_LOG_UPSTREAM_STATS ,
( upstream - > tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR ) ,
2018-02-07 10:08:55 -06:00
" %-40s : Verify failed : TLS - %s - "
2018-02-07 07:38:31 -06:00
" Pinset validation failure \n " , upstream - > addr_str ,
( upstream - > tls_fallback_ok
? " Tolerated because of Opportunistic profile "
: " *Failure* " ) ) ;
2018-02-08 07:04:02 -06:00
# elif defined(USE_DANESSL)
2018-02-07 07:38:31 -06:00
else if ( verify_result = = X509_V_ERR_CERT_UNTRUSTED
& & upstream - > tls_pubkey_pinset
& & ! DANESSL_get_match_cert (
upstream - > tls_obj , NULL , NULL , NULL ) )
_getdns_upstream_log ( upstream ,
GETDNS_LOG_UPSTREAM_STATS ,
( upstream - > tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR ) ,
2018-02-07 10:08:55 -06:00
" %-40s : Verify failed : TLS - %s - "
2018-02-07 07:38:31 -06:00
" Pinset validation failure \n " , upstream - > addr_str ,
( upstream - > tls_fallback_ok
? " Tolerated because of Opportunistic profile "
: " *Failure* " ) ) ;
2018-02-08 07:04:02 -06:00
# endif
2018-01-04 08:58:09 -06:00
else if ( verify_result ! = X509_V_OK )
_getdns_upstream_log ( upstream ,
GETDNS_LOG_UPSTREAM_STATS ,
( upstream - > tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR ) ,
2018-02-07 10:08:55 -06:00
" %-40s : Verify failed : TLS - %s - "
2018-01-04 08:58:09 -06:00
" (%d) \" %s \" \n " , upstream - > addr_str ,
( upstream - > tls_fallback_ok
2018-01-10 05:47:14 -06:00
? " Tolerated because of Opportunistic profile "
2018-01-04 08:58:09 -06:00
: " *Failure* " ) , verify_result ,
X509_verify_cert_error_string ( verify_result ) ) ;
2018-02-09 08:18:44 -06:00
# if !defined(HAVE_SSL_HN_AUTH) && !defined(HAVE_X509_CHECK_HOST)
2018-01-10 05:47:14 -06:00
else if ( * upstream - > tls_auth_name ) {
_getdns_upstream_log ( upstream ,
GETDNS_LOG_UPSTREAM_STATS ,
( upstream - > tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR ) ,
2018-02-07 10:08:55 -06:00
" %-40s : Verify failed : TLS - %s - "
2018-01-10 05:47:14 -06:00
" Hostname Authentication not available from TLS "
" library (check library version) \n " ,
upstream - > addr_str ,
( upstream - > tls_fallback_ok
? " Tolerated because of Opportunistic profile "
: " *Failure* " ) ) ;
upstream - > tls_auth_state = GETDNS_AUTH_FAILED ;
}
2018-02-08 07:04:02 -06:00
# endif
2018-01-04 08:58:09 -06:00
else
_getdns_upstream_log ( upstream ,
GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_DEBUG ,
2018-02-07 10:08:55 -06:00
" %-40s : Verify passed : TLS \n " ,
2018-01-04 09:15:50 -06:00
upstream - > addr_str ) ;
2018-01-04 08:58:09 -06:00
2018-01-10 05:47:14 -06:00
X509_free ( peer_cert ) ;
2018-01-04 08:58:09 -06:00
if ( upstream - > tls_auth_state = = GETDNS_AUTH_FAILED
& & ! upstream - > tls_fallback_ok )
return STUB_SETUP_ERROR ;
}
2016-12-07 11:01:03 -06:00
DEBUG_STUB ( " %s %-35s: FD: %d Handshake succeeded with auth state %s. Session is %s. \n " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_SETUP_TLS , __FUNC__ , upstream - > fd ,
2016-12-11 10:57:52 -06:00
_getdns_auth_str ( upstream - > tls_auth_state ) ,
2016-04-28 09:41:34 -05:00
SSL_session_reused ( upstream - > tls_obj ) ? " re-used " : " new " ) ;
2018-01-04 08:58:09 -06:00
upstream - > tls_hs_state = GETDNS_HS_DONE ;
upstream - > conn_state = GETDNS_CONN_OPEN ;
upstream - > conn_completed + + ;
2016-04-28 09:41:34 -05:00
if ( upstream - > tls_session ! = NULL )
SSL_SESSION_free ( upstream - > tls_session ) ;
upstream - > tls_session = SSL_get1_session ( upstream - > tls_obj ) ;
2015-05-03 09:11:46 -05:00
/* Reset timeout on success*/
2015-04-19 11:16:58 -05:00
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
2015-07-14 04:54:25 -05:00
upstream - > event . read_cb = NULL ;
upstream - > event . write_cb = upstream_write_cb ;
2015-05-03 09:11:46 -05:00
GETDNS_SCHEDULE_EVENT ( upstream - > loop , upstream - > fd , TIMEOUT_FOREVER ,
getdns_eventloop_event_init ( & upstream - > event , upstream ,
NULL , upstream_write_cb , NULL ) ) ;
2015-04-19 11:16:58 -05:00
return 0 ;
2014-12-07 13:03:34 -06:00
}
2015-04-27 09:32:57 -05:00
static int
2015-05-02 12:08:45 -05:00
tls_connected ( getdns_upstream * upstream )
2015-04-19 11:16:58 -05:00
{
2015-06-26 08:27:21 -05:00
/* Already have a TLS connection*/
2016-06-23 09:53:51 -05:00
if ( upstream - > tls_hs_state = = GETDNS_HS_DONE )
2015-04-19 11:16:58 -05:00
return 0 ;
2015-05-02 12:08:45 -05:00
/* Already tried and failed, so let the fallback code take care of things */
2015-04-24 10:29:08 -05:00
if ( upstream - > tls_hs_state = = GETDNS_HS_FAILED )
2016-06-23 09:53:51 -05:00
return STUB_SETUP_ERROR ;
2015-04-24 10:29:08 -05:00
2016-06-23 09:53:51 -05:00
/* Lets make sure the TCP connection is up before we try a handshake*/
2015-06-26 08:27:21 -05:00
int q = tcp_connected ( upstream ) ;
2016-06-23 09:53:51 -05:00
if ( q ! = 0 )
2015-06-26 08:27:21 -05:00
return q ;
2015-04-19 11:16:58 -05:00
2015-05-02 12:08:45 -05:00
return tls_do_handshake ( upstream ) ;
2015-04-19 11:16:58 -05:00
}
2015-05-02 12:08:45 -05:00
/***************************/
/* TLS read/write functions*/
/***************************/
2015-04-19 11:16:58 -05:00
static int
2015-05-02 12:08:45 -05:00
stub_tls_read ( getdns_upstream * upstream , getdns_tcp_state * tcp ,
struct mem_funcs * mf )
2014-12-07 13:03:34 -06:00
{
ssize_t read ;
uint8_t * buf ;
size_t buf_size ;
2015-04-19 11:16:58 -05:00
SSL * tls_obj = upstream - > tls_obj ;
2015-05-02 12:08:45 -05:00
int q = tls_connected ( upstream ) ;
2015-04-19 11:16:58 -05:00
if ( q ! = 0 )
return q ;
2014-12-07 13:03:34 -06:00
if ( ! tcp - > read_buf ) {
/* First time tls read, create a buffer for reading */
if ( ! ( tcp - > read_buf = GETDNS_XMALLOC ( * mf , uint8_t , 4096 ) ) )
return STUB_TCP_ERROR ;
tcp - > read_buf_len = 4096 ;
tcp - > read_pos = tcp - > read_buf ;
tcp - > to_read = 2 ; /* Packet size */
}
ERR_clear_error ( ) ;
read = SSL_read ( tls_obj , tcp - > read_pos , tcp - > to_read ) ;
if ( read < = 0 ) {
/* TODO[TLS]: Handle SSL_ERROR_WANT_WRITE which means handshake
renegotiation . Need to keep handshake state to do that . */
int want = SSL_get_error ( tls_obj , read ) ;
if ( want = = SSL_ERROR_WANT_READ ) {
2017-11-03 07:50:13 -05:00
return STUB_TCP_RETRY ; /* Come back later */
2014-12-07 13:03:34 -06:00
} else
return STUB_TCP_ERROR ;
}
tcp - > to_read - = read ;
tcp - > read_pos + = read ;
if ( ( int ) tcp - > to_read > 0 )
2017-11-03 07:50:13 -05:00
return STUB_TCP_MORE_TO_READ ;
2014-12-07 13:03:34 -06:00
read = tcp - > read_pos - tcp - > read_buf ;
if ( read = = 2 ) {
/* Read the packet size short */
tcp - > to_read = gldns_read_uint16 ( tcp - > read_buf ) ;
if ( tcp - > to_read < GLDNS_HEADER_SIZE )
return STUB_TCP_ERROR ;
/* Resize our buffer if needed */
if ( tcp - > to_read > tcp - > read_buf_len ) {
buf_size = tcp - > read_buf_len ;
while ( tcp - > to_read > buf_size )
buf_size * = 2 ;
if ( ! ( buf = GETDNS_XREALLOC ( * mf ,
tcp - > read_buf , uint8_t , buf_size ) ) )
return STUB_TCP_ERROR ;
tcp - > read_buf = buf ;
tcp - > read_buf_len = buf_size ;
}
/* Ready to start reading the packet */
tcp - > read_pos = tcp - > read_buf ;
read = SSL_read ( tls_obj , tcp - > read_pos , tcp - > to_read ) ;
if ( read < = 0 ) {
/* TODO[TLS]: Handle SSL_ERROR_WANT_WRITE which means handshake
renegotiation . Need to keep handshake state to do that . */
int want = SSL_get_error ( tls_obj , read ) ;
if ( want = = SSL_ERROR_WANT_READ ) {
2017-11-03 07:50:13 -05:00
return STUB_TCP_RETRY ; /* read more later */
2014-12-07 13:03:34 -06:00
} else
return STUB_TCP_ERROR ;
}
tcp - > to_read - = read ;
tcp - > read_pos + = read ;
if ( ( int ) tcp - > to_read > 0 )
2017-11-03 07:50:13 -05:00
return STUB_TCP_MORE_TO_READ ;
2014-12-07 13:03:34 -06:00
}
return GLDNS_ID_WIRE ( tcp - > read_buf ) ;
}
2014-10-17 17:25:41 -05:00
static int
2015-05-02 12:08:45 -05:00
stub_tls_write ( getdns_upstream * upstream , getdns_tcp_state * tcp ,
getdns_network_req * netreq )
2014-10-17 17:25:41 -05:00
{
2015-10-31 05:04:56 -05:00
size_t pkt_len ;
2014-10-24 16:12:28 -05:00
ssize_t written ;
2014-10-17 17:25:41 -05:00
uint16_t query_id ;
intptr_t query_id_intptr ;
2015-05-02 12:08:45 -05:00
SSL * tls_obj = upstream - > tls_obj ;
2015-11-01 00:58:12 -05:00
uint16_t padding_sz ;
2015-05-02 12:08:45 -05:00
int q = tls_connected ( upstream ) ;
if ( q ! = 0 )
return q ;
2016-06-23 09:53:51 -05:00
/* This is the case where the upstream is connected but it isn't an authenticated
connection , but the request needs an authenticated connection . For now , we
fail the write as a special case , since other oppotunistic requests can still use
this upstream . but this needs more thought : Should we open a second connection ? */
if ( ! upstream_auth_status_ok ( upstream , netreq ) )
return STUB_NO_AUTH ;
2014-10-17 17:25:41 -05:00
2014-10-24 16:12:28 -05:00
/* Do we have remaining data that we could not write before? */
2014-10-17 17:25:41 -05:00
if ( ! tcp - > write_buf ) {
2015-02-03 03:46:44 -06:00
/* No, this is an initial write. Try to send
2014-10-24 16:12:28 -05:00
*/
2014-10-17 17:25:41 -05:00
2015-05-02 12:08:45 -05:00
/* Find a unique query_id not already written (or in
2014-10-17 17:25:41 -05:00
* the write_queue ) for that upstream . Register this netreq
* by query_id in the process .
*/
2015-05-02 12:08:45 -05:00
do {
2015-06-11 04:21:12 -05:00
query_id = arc4random ( ) ;
2014-10-17 17:25:41 -05:00
query_id_intptr = ( intptr_t ) query_id ;
netreq - > node . key = ( void * ) query_id_intptr ;
2015-08-19 09:07:01 -05:00
} while ( ! _getdns_rbtree_insert (
2014-10-17 17:25:41 -05:00
& netreq - > upstream - > netreq_by_query_id , & netreq - > node ) ) ;
2017-10-17 06:47:29 -05:00
netreq - > query_id_registered = & netreq - > upstream - > netreq_by_query_id ;
2014-10-17 17:25:41 -05:00
2015-02-03 03:46:44 -06:00
GLDNS_ID_SET ( netreq - > query , query_id ) ;
2017-06-15 10:21:05 -05:00
2015-11-24 11:59:01 -06:00
/* TODO: Review if more EDNS0 handling can be centralised.*/
2015-10-31 05:04:56 -05:00
if ( netreq - > opt ) {
_getdns_network_req_clear_upstream_options ( netreq ) ;
2015-02-12 05:03:20 -06:00
/* no limits on the max udp payload size with tcp */
gldns_write_uint16 ( netreq - > opt + 3 , 65535 ) ;
2015-10-31 05:04:56 -05:00
/* we do not edns_cookie over TLS, since TLS
* provides stronger guarantees than cookies
* already */
2015-10-31 22:20:12 -05:00
if ( netreq - > owner - > edns_client_subnet_private )
if ( attach_edns_client_subnet_private ( netreq ) )
return STUB_OUT_OF_OPTIONS ;
2016-06-23 09:53:51 -05:00
if ( netreq - > upstream - > queries_sent % EDNS_KEEPALIVE_RESEND = = 0 & &
2015-11-24 11:59:01 -06:00
netreq - > owner - > context - > idle_timeout ! = 0 ) {
/* Add the keepalive option to every nth query on this
connection */
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d Requesting keepalive \n " ,
2016-12-12 06:55:10 -06:00
STUB_DEBUG_SETUP , __FUNC__ , upstream - > fd ) ;
2015-11-24 11:59:01 -06:00
if ( attach_edns_keepalive ( netreq ) )
return STUB_OUT_OF_OPTIONS ;
netreq - > keepalive_sent = 1 ;
}
2017-03-26 14:06:29 -05:00
if ( netreq - > owner - > tls_query_padding_blocksize > 0 ) {
uint16_t blksz = netreq - > owner - > tls_query_padding_blocksize ;
if ( blksz = = 1 ) /* use a sensible default policy */
blksz = 128 ;
2015-11-01 00:58:12 -05:00
pkt_len = netreq - > response - netreq - > query ;
pkt_len + = 4 ; /* this accounts for the OPTION-CODE and OPTION-LENGTH of the padding */
2017-03-26 14:06:29 -05:00
padding_sz = pkt_len % blksz ;
2015-11-01 00:58:12 -05:00
if ( padding_sz )
2017-03-26 14:06:29 -05:00
padding_sz = blksz - padding_sz ;
2015-11-01 00:58:12 -05:00
if ( _getdns_network_req_add_upstream_option ( netreq ,
EDNS_PADDING_OPCODE ,
padding_sz , NULL ) )
return STUB_OUT_OF_OPTIONS ;
}
2015-10-31 05:04:56 -05:00
}
2014-10-17 17:25:41 -05:00
2015-12-21 15:11:16 -06:00
pkt_len = _getdns_network_req_add_tsig ( netreq ) ;
2014-10-17 17:25:41 -05:00
/* We have an initialized packet buffer.
2015-05-02 12:08:45 -05:00
* Lets see how much of it we can write */
/* TODO[TLS]: Handle error cases, partial writes, renegotiation etc. */
ERR_clear_error ( ) ;
2017-04-06 04:20:08 -05:00
# if INTERCEPT_COM_DS
/* Intercept and do not sent out COM DS queries. For debugging
* purposes only . Never commit with this turned on .
*/
if ( netreq - > request_type = = GETDNS_RRTYPE_DS & &
netreq - > owner - > name_len = = 5 & &
netreq - > owner - > name [ 0 ] = = 3 & &
( netreq - > owner - > name [ 1 ] & 0xDF ) = = ' C ' & &
( netreq - > owner - > name [ 2 ] & 0xDF ) = = ' O ' & &
( netreq - > owner - > name [ 3 ] & 0xDF ) = = ' M ' & &
netreq - > owner - > name [ 4 ] = = 0 ) {
debug_req ( " Intercepting " , netreq ) ;
written = pkt_len + 2 ;
} else
# endif
2015-05-02 12:08:45 -05:00
written = SSL_write ( tls_obj , netreq - > query - 2 , pkt_len + 2 ) ;
2017-04-06 04:46:10 -05:00
if ( written < = 0 ) {
/* SSL_write will not do partial writes, because
* SSL_MODE_ENABLE_PARTIAL_WRITE is not default ,
* but the write could fail because of renegotiation .
* In that case SSL_get_error ( ) will return
* SSL_ERROR_WANT_READ or , SSL_ERROR_WANT_WRITE .
* Return for retry in such cases .
*/
switch ( SSL_get_error ( tls_obj , written ) ) {
case SSL_ERROR_WANT_READ :
case SSL_ERROR_WANT_WRITE :
2017-11-03 07:50:13 -05:00
return STUB_TCP_RETRY ;
2017-04-06 04:46:10 -05:00
default :
return STUB_TCP_ERROR ;
}
}
2014-10-17 17:25:41 -05:00
/* We were able to write everything! Start reading. */
2015-02-03 03:46:44 -06:00
return ( int ) query_id ;
2014-10-17 17:25:41 -05:00
2015-05-02 12:08:45 -05:00
}
2014-10-17 17:25:41 -05:00
2015-05-02 12:08:45 -05:00
return STUB_TCP_ERROR ;
}
2016-12-22 17:51:47 -06:00
uint64_t
2015-10-31 22:47:49 -05:00
_getdns_get_time_as_uintt64 ( ) {
2016-12-05 13:38:59 -06:00
2015-10-31 22:47:49 -05:00
struct timeval tv ;
uint64_t now ;
2016-12-05 13:38:59 -06:00
2015-10-31 22:47:49 -05:00
if ( gettimeofday ( & tv , NULL ) ) {
return 0 ;
}
now = tv . tv_sec * 1000000 + tv . tv_usec ;
return now ;
}
2016-12-05 13:38:59 -06:00
2015-05-02 12:08:45 -05:00
/**************************/
/* UDP callback functions */
/**************************/
2017-03-22 04:52:55 -05:00
2015-05-02 12:08:45 -05:00
static void
stub_udp_read_cb ( void * userarg )
{
getdns_network_req * netreq = ( getdns_network_req * ) userarg ;
getdns_dns_req * dnsreq = netreq - > owner ;
getdns_upstream * upstream = netreq - > upstream ;
ssize_t read ;
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: MSG: %p \n " , STUB_DEBUG_READ ,
2016-12-12 07:20:31 -06:00
__FUNC__ , ( void * ) netreq ) ;
2015-05-02 12:08:45 -05:00
2015-12-24 07:41:50 -06:00
read = recvfrom ( netreq - > fd , ( void * ) netreq - > response ,
2015-05-02 12:08:45 -05:00
netreq - > max_udp_payload_size + 1 , /* If read == max_udp_payload_size
* then all is good . If read = =
* max_udp_payload_size + 1 , then
* we receive more then requested !
* i . e . overflow
*/
0 , NULL , NULL ) ;
2017-11-03 10:42:38 -05:00
if ( read = = - 1 & & ( _getdns_socketerror_wants_retry ( ) | |
2017-10-04 11:31:33 -05:00
_getdns_socketerror ( ) = = _getdns_ECONNRESET ) )
2017-03-22 04:52:55 -05:00
return ; /* Try again later */
if ( read = = - 1 ) {
DEBUG_STUB ( " %s %-35s: MSG: %p error while reading from socket: "
" %s \n " , STUB_DEBUG_READ , __FUNC__ , ( void * ) netreq
2017-11-03 07:50:13 -05:00
, _getdns_errnostr ( ) ) ;
2015-05-02 12:08:45 -05:00
2017-03-22 04:52:55 -05:00
stub_cleanup ( netreq ) ;
_getdns_netreq_change_state ( netreq , NET_REQ_ERRORED ) ;
/* Handle upstream*/
if ( netreq - > fd > = 0 ) {
2017-10-04 11:31:33 -05:00
_getdns_closesocket ( netreq - > fd ) ;
2017-07-31 16:48:09 -05:00
netreq - > fd = - 1 ;
2017-03-22 04:52:55 -05:00
stub_next_upstream ( netreq ) ;
}
netreq - > debug_end_time = _getdns_get_time_as_uintt64 ( ) ;
_getdns_check_dns_req_complete ( netreq - > owner ) ;
return ;
}
2015-05-02 12:08:45 -05:00
if ( read < GLDNS_HEADER_SIZE )
return ; /* Not DNS */
2017-06-15 14:24:40 -05:00
if ( GLDNS_ID_WIRE ( netreq - > response ) ! = GLDNS_ID_WIRE ( netreq - > query ) )
2015-05-02 12:08:45 -05:00
return ; /* Cache poisoning attempt ;) */
if ( netreq - > owner - > edns_cookies & & match_and_process_server_cookie (
upstream , netreq - > response , read ) )
return ; /* Client cookie didn't match? */
2017-02-18 08:56:06 -06:00
GETDNS_CLEAR_EVENT ( dnsreq - > loop , & netreq - > event ) ;
2017-10-04 11:31:33 -05:00
_getdns_closesocket ( netreq - > fd ) ;
2017-07-31 16:48:09 -05:00
netreq - > fd = - 1 ;
2015-12-22 03:56:20 -06:00
while ( GLDNS_TC_WIRE ( netreq - > response ) ) {
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: MSG: %p TC bit set in response \n " , STUB_DEBUG_READ ,
2016-12-12 07:20:31 -06:00
__FUNC__ , ( void * ) netreq ) ;
2015-06-19 12:28:29 -05:00
if ( ! ( netreq - > transport_current < netreq - > transport_count ) )
2015-12-22 03:56:20 -06:00
break ;
2015-06-21 10:55:12 -05:00
getdns_transport_list_t next_transport =
netreq - > transports [ + + netreq - > transport_current ] ;
2015-12-22 03:56:20 -06:00
if ( next_transport ! = GETDNS_TRANSPORT_TCP & &
next_transport ! = GETDNS_TRANSPORT_TLS )
break ;
2015-06-22 12:02:28 -05:00
/* For now, special case where fallback should be on the same upstream*/
2015-06-21 10:55:12 -05:00
if ( ( netreq - > fd = upstream_connect ( upstream , next_transport ,
2015-06-19 12:28:29 -05:00
dnsreq ) ) = = - 1 )
2015-12-22 03:56:20 -06:00
break ;
2015-06-21 10:55:12 -05:00
upstream_schedule_netreq ( netreq - > upstream , netreq ) ;
2017-03-13 08:20:47 -05:00
GETDNS_SCHEDULE_EVENT ( dnsreq - > loop , - 1 ,
_getdns_ms_until_expiry ( dnsreq - > expires ) ,
2016-04-11 07:49:44 -05:00
getdns_eventloop_event_init ( & netreq - > event ,
netreq , NULL , NULL , stub_timeout_cb ) ) ;
2014-10-17 17:25:41 -05:00
2015-05-02 12:08:45 -05:00
return ;
}
netreq - > response_len = read ;
2017-03-17 12:16:14 -05:00
if ( ! dnsreq - > context - > round_robin_upstreams )
dnsreq - > upstreams - > current_udp = 0 ;
else {
dnsreq - > upstreams - > current_udp + = GETDNS_UPSTREAM_TRANSPORTS ;
if ( dnsreq - > upstreams - > current_udp > = dnsreq - > upstreams - > count )
dnsreq - > upstreams - > current_udp = 0 ;
}
2015-10-31 22:47:49 -05:00
netreq - > debug_end_time = _getdns_get_time_as_uintt64 ( ) ;
2017-03-14 11:17:56 -05:00
_getdns_netreq_change_state ( netreq , NET_REQ_FINISHED ) ;
2016-12-05 12:05:04 -06:00
upstream - > udp_responses + + ;
2018-02-26 09:42:51 -06:00
upstream - > back_off = 1 ;
2016-12-06 08:44:40 -06:00
if ( upstream - > udp_responses = = 1 | |
upstream - > udp_responses % 100 = = 0 )
2017-09-12 09:01:02 -05:00
_getdns_upstream_log ( upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_INFO ,
2018-01-24 07:13:14 -06:00
" %-40s : Upstream : UDP - Resps=%6d, Timeouts =%6d (logged every 100 responses) \n " ,
2017-06-28 14:09:40 -05:00
upstream - > addr_str ,
2017-06-26 17:23:22 -05:00
( int ) upstream - > udp_responses , ( int ) upstream - > udp_timeouts ) ;
2015-08-19 09:22:38 -05:00
_getdns_check_dns_req_complete ( dnsreq ) ;
2015-05-02 12:08:45 -05:00
}
static void
stub_udp_write_cb ( void * userarg )
{
getdns_network_req * netreq = ( getdns_network_req * ) userarg ;
getdns_dns_req * dnsreq = netreq - > owner ;
2015-10-31 05:04:56 -05:00
size_t pkt_len ;
2017-06-14 08:36:53 -05:00
ssize_t written ;
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: MSG: %p \n " , STUB_DEBUG_WRITE ,
2016-12-12 06:55:10 -06:00
__FUNC__ , ( void * ) netreq ) ;
2015-05-02 12:08:45 -05:00
GETDNS_CLEAR_EVENT ( dnsreq - > loop , & netreq - > event ) ;
2015-10-31 22:47:49 -05:00
netreq - > debug_start_time = _getdns_get_time_as_uintt64 ( ) ;
2015-11-13 07:28:43 -06:00
netreq - > debug_udp = 1 ;
2017-06-15 14:24:40 -05:00
GLDNS_ID_SET ( netreq - > query , ( uint16_t ) arc4random ( ) ) ;
2015-05-02 12:08:45 -05:00
if ( netreq - > opt ) {
2015-10-31 05:04:56 -05:00
_getdns_network_req_clear_upstream_options ( netreq ) ;
2015-05-02 12:08:45 -05:00
if ( netreq - > edns_maximum_udp_payload_size = = - 1 )
gldns_write_uint16 ( netreq - > opt + 3 ,
( netreq - > max_udp_payload_size =
netreq - > upstream - > addr . ss_family = = AF_INET6
? 1232 : 1432 ) ) ;
2015-10-31 05:04:56 -05:00
if ( netreq - > owner - > edns_cookies )
if ( attach_edns_cookie ( netreq ) )
return ; /* too many upstream options */
2015-10-31 22:20:12 -05:00
if ( netreq - > owner - > edns_client_subnet_private )
if ( attach_edns_client_subnet_private ( netreq ) )
return ; /* too many upstream options */
2015-05-02 12:08:45 -05:00
}
2015-12-21 15:11:16 -06:00
pkt_len = _getdns_network_req_add_tsig ( netreq ) ;
2017-06-14 08:36:53 -05:00
if ( ( ssize_t ) pkt_len ! = ( written = sendto (
2015-12-24 07:41:50 -06:00
netreq - > fd , ( const void * ) netreq - > query , pkt_len , 0 ,
2015-05-02 12:08:45 -05:00
( struct sockaddr * ) & netreq - > upstream - > addr ,
2017-06-14 08:36:53 -05:00
netreq - > upstream - > addr_len ) ) ) {
# if defined(STUB_DEBUG) && STUB_DEBUG
if ( written = = - 1 )
DEBUG_STUB ( " %s %-35s: MSG: %p error: %s \n "
, STUB_DEBUG_WRITE , __FUNC__ , ( void * ) netreq
2017-11-03 07:50:13 -05:00
, _getdns_errnostr ( ) ) ;
2017-06-14 08:36:53 -05:00
else
2018-02-23 16:11:46 -06:00
DEBUG_STUB ( " %s %-35s: MSG: %p returned: %d, expected: %d \n "
2017-06-14 08:36:53 -05:00
, STUB_DEBUG_WRITE , __FUNC__ , ( void * ) netreq
, ( int ) written , ( int ) pkt_len ) ;
# endif
stub_cleanup ( netreq ) ;
_getdns_netreq_change_state ( netreq , NET_REQ_ERRORED ) ;
/* Handle upstream*/
if ( netreq - > fd > = 0 ) {
2017-10-04 11:31:33 -05:00
_getdns_closesocket ( netreq - > fd ) ;
2017-07-31 16:48:09 -05:00
netreq - > fd = - 1 ;
2017-06-14 08:36:53 -05:00
stub_next_upstream ( netreq ) ;
}
netreq - > debug_end_time = _getdns_get_time_as_uintt64 ( ) ;
_getdns_check_dns_req_complete ( netreq - > owner ) ;
2015-05-02 12:08:45 -05:00
return ;
}
2017-03-13 08:20:47 -05:00
GETDNS_SCHEDULE_EVENT ( dnsreq - > loop , netreq - > fd ,
_getdns_ms_until_expiry ( dnsreq - > expires ) ,
2015-05-02 12:08:45 -05:00
getdns_eventloop_event_init ( & netreq - > event , netreq ,
stub_udp_read_cb , NULL , stub_timeout_cb ) ) ;
}
/**************************/
/* Upstream callback functions*/
/**************************/
static void
2016-03-23 16:13:31 -05:00
process_finished_cb ( void * userarg )
2014-12-07 13:03:34 -06:00
{
2015-05-02 12:08:45 -05:00
getdns_upstream * upstream = ( getdns_upstream * ) userarg ;
2016-03-23 16:13:31 -05:00
getdns_dns_req * dnsreq ;
2016-04-11 07:49:44 -05:00
/* Upstream->loop is always the async one, because finished_events
* are only scheduled against ( and thus fired from ) the async loop
*/
2016-03-23 16:13:31 -05:00
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > finished_event ) ;
upstream - > finished_event . timeout_cb = NULL ;
while ( upstream - > finished_dnsreqs ) {
dnsreq = upstream - > finished_dnsreqs ;
upstream - > finished_dnsreqs = dnsreq - > finished_next ;
_getdns_check_dns_req_complete ( dnsreq ) ;
}
}
static void
2016-04-11 07:49:44 -05:00
upstream_read_cb ( void * userarg )
2016-03-23 16:13:31 -05:00
{
2016-04-11 07:49:44 -05:00
getdns_upstream * upstream = ( getdns_upstream * ) userarg ;
2016-12-12 06:55:10 -06:00
DEBUG_STUB ( " %s %-35s: FD: %d \n " , STUB_DEBUG_READ , __FUNC__ ,
2016-03-01 12:05:01 -06:00
upstream - > fd ) ;
2015-05-02 12:08:45 -05:00
getdns_network_req * netreq ;
int q ;
uint16_t query_id ;
intptr_t query_id_intptr ;
2016-03-23 16:13:31 -05:00
getdns_dns_req * dnsreq ;
2015-04-19 11:16:58 -05:00
2016-06-23 09:53:51 -05:00
if ( upstream - > transport = = GETDNS_TRANSPORT_TLS )
2015-05-02 12:08:45 -05:00
q = stub_tls_read ( upstream , & upstream - > tcp ,
2016-01-12 08:52:14 -06:00
& upstream - > upstreams - > mf ) ;
2015-05-02 12:08:45 -05:00
else
q = stub_tcp_read ( upstream - > fd , & upstream - > tcp ,
2016-01-12 08:52:14 -06:00
& upstream - > upstreams - > mf ) ;
2014-12-07 13:03:34 -06:00
2015-05-02 12:08:45 -05:00
switch ( q ) {
2017-11-03 07:50:13 -05:00
case STUB_TCP_MORE_TO_READ :
2016-01-12 08:52:14 -06:00
/* WSA TODO: if callback is still upstream_read_cb, do it again
*/
2017-11-03 07:50:13 -05:00
case STUB_TCP_RETRY :
2015-05-02 12:08:45 -05:00
return ;
2016-06-23 09:53:51 -05:00
case STUB_SETUP_ERROR : /* Can happen for TLS HS*/
2015-05-02 12:08:45 -05:00
case STUB_TCP_ERROR :
2016-06-23 09:53:51 -05:00
upstream_failed ( upstream , ( q = = STUB_TCP_ERROR ? 0 : 1 ) ) ;
2015-05-02 12:08:45 -05:00
return ;
2014-12-07 13:03:34 -06:00
2015-05-02 12:08:45 -05:00
default :
/* Lookup netreq */
query_id = ( uint16_t ) q ;
query_id_intptr = ( intptr_t ) query_id ;
2015-08-19 09:07:01 -05:00
netreq = ( getdns_network_req * ) _getdns_rbtree_delete (
2015-05-02 12:08:45 -05:00
& upstream - > netreq_by_query_id , ( void * ) query_id_intptr ) ;
if ( ! netreq ) /* maybe canceled */ {
/* reset read buffer */
upstream - > tcp . read_pos = upstream - > tcp . read_buf ;
upstream - > tcp . to_read = 2 ;
return ;
}
2017-10-17 06:47:29 -05:00
if ( netreq - > query_id_registered = = & upstream - > netreq_by_query_id ) {
netreq - > query_id_registered = NULL ;
netreq - > node . key = NULL ;
} else if ( netreq - > query_id_registered ) {
( void ) _getdns_rbtree_delete (
netreq - > query_id_registered , netreq - > node . key ) ;
netreq - > query_id_registered = NULL ;
netreq - > node . key = NULL ;
}
2016-04-11 07:49:44 -05:00
DEBUG_STUB ( " %s %-35s: MSG: %p (read) \n " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_READ , __FUNC__ , ( void * ) netreq ) ;
2017-03-14 11:17:56 -05:00
_getdns_netreq_change_state ( netreq , NET_REQ_FINISHED ) ;
2015-05-02 12:08:45 -05:00
netreq - > response = upstream - > tcp . read_buf ;
netreq - > response_len =
upstream - > tcp . read_pos - upstream - > tcp . read_buf ;
upstream - > tcp . read_buf = NULL ;
2015-06-29 03:09:13 -05:00
upstream - > responses_received + + ;
2015-11-24 11:59:01 -06:00
2016-03-23 16:13:31 -05:00
/* !THIS CODE NEEDS TESTING! */
2015-11-24 11:59:01 -06:00
if ( netreq - > owner - > edns_cookies & &
match_and_process_server_cookie (
2016-06-23 09:53:51 -05:00
netreq - > upstream , upstream - > tcp . read_buf ,
upstream - > tcp . read_pos - upstream - > tcp . read_buf ) )
2016-04-13 05:06:51 -05:00
return ; /* Client cookie didn't match (or FORMERR) */
2014-12-07 13:03:34 -06:00
2016-04-13 05:06:51 -05:00
if ( netreq - > owner - > context - > idle_timeout ! = 0 )
2015-11-24 11:59:01 -06:00
process_keepalive ( netreq - > upstream , netreq , netreq - > response ,
2016-04-13 05:06:51 -05:00
netreq - > response_len ) ;
2015-05-02 12:08:45 -05:00
2015-10-31 22:47:49 -05:00
netreq - > debug_end_time = _getdns_get_time_as_uintt64 ( ) ;
2015-06-25 14:21:00 -05:00
/* This also reschedules events for the upstream*/
stub_cleanup ( netreq ) ;
2016-04-11 08:33:08 -05:00
if ( ! upstream - > is_sync_loop | | netreq - > owner - > is_sync_request )
2016-03-23 16:13:31 -05:00
_getdns_check_dns_req_complete ( netreq - > owner ) ;
2016-04-11 08:33:08 -05:00
else {
assert ( upstream - > is_sync_loop & &
! netreq - > owner - > is_sync_request ) ;
2016-03-23 16:13:31 -05:00
2016-04-11 07:49:44 -05:00
/* We have a result for an asynchronously scheduled
* netreq , while processing the synchronous loop .
2016-03-23 16:13:31 -05:00
* Queue dns_req_complete checks .
*/
/* First check if one for the dns_req already exists */
for ( dnsreq = upstream - > finished_dnsreqs
; dnsreq & & dnsreq ! = netreq - > owner
; dnsreq = dnsreq - > finished_next )
; /* pass */
if ( ! dnsreq ) {
/* Schedule dns_req_complete check for this
* netreq ' s owner
*/
dnsreq = netreq - > owner ;
dnsreq - > finished_next =
upstream - > finished_dnsreqs ;
upstream - > finished_dnsreqs = dnsreq ;
if ( ! upstream - > finished_event . timeout_cb ) {
upstream - > finished_event . timeout_cb
= process_finished_cb ;
2016-04-11 07:49:44 -05:00
GETDNS_SCHEDULE_EVENT (
dnsreq - > context - > extension ,
2016-03-23 16:13:31 -05:00
- 1 , 1 , & upstream - > finished_event ) ;
}
}
}
2016-01-12 08:52:14 -06:00
/* WSA TODO: if callback is still upstream_read_cb, do it again
*/
return ;
2015-05-02 12:08:45 -05:00
}
2014-12-07 13:03:34 -06:00
}
2014-10-18 07:32:55 -05:00
static void
upstream_write_cb ( void * userarg )
{
getdns_upstream * upstream = ( getdns_upstream * ) userarg ;
getdns_network_req * netreq = upstream - > write_queue ;
int q ;
2017-03-25 13:36:20 -05:00
X509 * cert ;
2016-06-23 09:53:51 -05:00
2015-11-15 11:46:21 -06:00
if ( ! netreq ) {
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
upstream - > event . write_cb = NULL ;
return ;
}
2016-06-23 09:53:51 -05:00
2015-10-31 22:47:49 -05:00
netreq - > debug_start_time = _getdns_get_time_as_uintt64 ( ) ;
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: MSG: %p (writing) \n " , STUB_DEBUG_WRITE ,
2016-12-12 07:20:31 -06:00
__FUNC__ , ( void * ) netreq ) ;
2016-03-01 12:05:01 -06:00
2016-06-23 09:53:51 -05:00
/* Health checks on current connection */
2017-07-06 00:43:31 -05:00
if ( upstream - > conn_state = = GETDNS_CONN_TEARDOWN | |
upstream - > conn_state = = GETDNS_CONN_CLOSED | |
upstream - > fd = = - 1 )
2016-06-23 09:53:51 -05:00
q = STUB_CONN_GONE ;
else if ( ! upstream_working_ok ( upstream ) )
q = STUB_TCP_ERROR ;
/* Seems ok, now try to write */
else if ( tls_requested ( netreq ) )
2015-04-19 11:16:58 -05:00
q = stub_tls_write ( upstream , & upstream - > tcp , netreq ) ;
2014-12-07 13:03:34 -06:00
else
q = stub_tcp_write ( upstream - > fd , & upstream - > tcp , netreq ) ;
switch ( q ) {
2017-11-03 07:50:13 -05:00
case STUB_TCP_MORE_TO_WRITE :
2016-01-12 08:52:14 -06:00
/* WSA TODO: if callback is still upstream_write_cb, do it again
*/
2017-11-03 07:50:13 -05:00
case STUB_TCP_RETRY :
2014-10-18 07:32:55 -05:00
return ;
2017-06-15 14:15:00 -05:00
case STUB_OUT_OF_OPTIONS :
2014-10-18 07:32:55 -05:00
case STUB_TCP_ERROR :
2016-06-23 09:53:51 -05:00
/* New problem with the TCP connection itself. Need to fallback.*/
2015-06-25 14:21:00 -05:00
/* Fall through */
2016-06-23 09:53:51 -05:00
case STUB_SETUP_ERROR :
/* Could not complete the set up. Need to fallback.*/
2016-11-12 22:14:03 -06:00
DEBUG_STUB ( " %s %-35s: Upstream: %p ERROR = %d \n " , STUB_DEBUG_WRITE ,
2016-12-12 07:20:31 -06:00
__FUNC__ , ( void * ) userarg , q ) ;
2016-06-23 09:53:51 -05:00
upstream_failed ( upstream , ( q = = STUB_TCP_ERROR ? 0 : 1 ) ) ;
2017-10-17 06:47:29 -05:00
return ;
2016-06-23 09:53:51 -05:00
case STUB_CONN_GONE :
case STUB_NO_AUTH :
/* Cleaning up after connection or auth check failure. Need to fallback. */
2015-06-25 14:21:00 -05:00
stub_cleanup ( netreq ) ;
2017-06-28 13:57:53 -05:00
_getdns_upstream_log ( upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_DEBUG ,
2018-01-24 07:13:14 -06:00
" %-40s : Conn closed: %s - *Failure* \n " ,
2017-06-28 14:09:40 -05:00
upstream - > addr_str ,
2017-06-26 17:23:22 -05:00
( upstream - > transport = = GETDNS_TRANSPORT_TLS ? " TLS " : " TCP " ) ) ;
2017-06-15 14:15:00 -05:00
if ( fallback_on_write ( netreq ) = = STUB_TCP_ERROR ) {
2016-06-23 09:53:51 -05:00
/* TODO: Need new state to report transport unavailable*/
2017-06-14 08:36:53 -05:00
_getdns_netreq_change_state ( netreq , NET_REQ_ERRORED ) ;
2015-08-19 09:22:38 -05:00
_getdns_check_dns_req_complete ( netreq - > owner ) ;
2015-06-25 14:21:00 -05:00
}
2015-04-19 11:16:58 -05:00
return ;
2014-10-18 07:32:55 -05:00
default :
2017-10-17 06:47:29 -05:00
/* Unqueue the netreq from the write_queue */
remove_from_write_queue ( upstream , netreq ) ;
2017-03-25 15:33:30 -05:00
if ( netreq - > owner - > return_call_reporting & &
2018-01-18 07:59:46 -06:00
netreq - > upstream - > tls_obj ) {
if ( netreq - > debug_tls_peer_cert . data = = NULL & &
( cert = SSL_get_peer_certificate ( netreq - > upstream - > tls_obj ) ) ) {
netreq - > debug_tls_peer_cert . size = i2d_X509 (
cert , & netreq - > debug_tls_peer_cert . data ) ;
X509_free ( cert ) ;
}
netreq - > debug_tls_version = SSL_get_version ( netreq - > upstream - > tls_obj ) ;
2017-03-25 15:26:05 -05:00
}
2016-06-23 09:53:51 -05:00
/* Need this because auth status is reset on connection close */
netreq - > debug_tls_auth_status = netreq - > upstream - > tls_auth_state ;
upstream - > queries_sent + + ;
2017-06-15 10:21:05 -05:00
2017-10-16 07:17:49 -05:00
/* Empty write_queue?, then deschedule upstream write_cb */
if ( upstream - > write_queue = = NULL ) {
assert ( upstream - > write_queue_last = = NULL ) ;
2015-08-17 05:35:10 -05:00
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
2014-10-18 07:32:55 -05:00
upstream - > event . write_cb = NULL ;
/* Reschedule (if already reading) to clear writable */
2014-10-19 15:51:42 -05:00
if ( upstream - > event . read_cb ) {
2014-10-18 07:32:55 -05:00
GETDNS_SCHEDULE_EVENT ( upstream - > loop ,
upstream - > fd , TIMEOUT_FOREVER ,
& upstream - > event ) ;
2014-10-19 15:51:42 -05:00
}
2014-10-18 07:32:55 -05:00
}
/* Schedule reading (if not already scheduled) */
if ( ! upstream - > event . read_cb ) {
2014-10-19 15:51:42 -05:00
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
2015-07-14 04:54:25 -05:00
upstream - > event . read_cb = upstream_read_cb ;
2014-10-18 07:32:55 -05:00
GETDNS_SCHEDULE_EVENT ( upstream - > loop ,
upstream - > fd , TIMEOUT_FOREVER , & upstream - > event ) ;
}
2016-01-12 08:52:14 -06:00
/* WSA TODO: if callback is still upstream_write_cb, do it again
*/
2014-10-18 07:32:55 -05:00
return ;
}
}
2015-05-02 12:08:45 -05:00
/*****************************/
/* Upstream utility functions*/
/*****************************/
2015-04-19 11:16:58 -05:00
2015-05-02 12:08:45 -05:00
static int
2016-06-23 09:53:51 -05:00
upstream_working_ok ( getdns_upstream * upstream )
{
/* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/
return ( upstream - > responses_timeouts >
2017-03-17 09:43:26 -05:00
upstream - > responses_received *
upstream - > upstreams - > tls_connection_retries ? 0 : 1 ) ;
2016-06-23 09:53:51 -05:00
}
static int
upstream_active ( getdns_upstream * upstream )
{
2016-07-21 12:24:18 -05:00
if ( ( upstream - > conn_state = = GETDNS_CONN_SETUP | |
upstream - > conn_state = = GETDNS_CONN_OPEN ) & &
upstream - > keepalive_shutdown = = 0 )
return 1 ;
return 0 ;
2016-06-23 09:53:51 -05:00
}
2017-03-16 09:51:46 -05:00
static int
2017-09-12 07:47:56 -05:00
upstream_usable ( getdns_upstream * upstream , int backoff_ok )
2017-03-16 09:51:46 -05:00
{
2017-09-13 04:00:56 -05:00
/* If backoff_ok is not true then only use upstreams that are in a healthy
state . */
2017-03-16 09:51:46 -05:00
if ( ( upstream - > conn_state = = GETDNS_CONN_CLOSED | |
upstream - > conn_state = = GETDNS_CONN_SETUP | |
upstream - > conn_state = = GETDNS_CONN_OPEN ) & &
upstream - > keepalive_shutdown = = 0 )
return 1 ;
2017-09-13 04:00:56 -05:00
/* Otherwise, allow upstreams that are backed off to be used because that
is better that having no upstream at all . */
2017-09-12 07:47:56 -05:00
if ( backoff_ok = = 1 & &
upstream - > conn_state = = GETDNS_CONN_BACKOFF )
return 1 ;
2017-03-16 09:51:46 -05:00
return 0 ;
}
2016-06-23 09:53:51 -05:00
static int
upstream_auth_status_ok ( getdns_upstream * upstream , getdns_network_req * netreq ) {
if ( netreq - > tls_auth_min ! = GETDNS_AUTHENTICATION_REQUIRED )
return 1 ;
return ( upstream - > tls_auth_state = = GETDNS_AUTH_OK ? 1 : 0 ) ;
}
static int
upstream_stats ( getdns_upstream * upstream )
{
/* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/
return ( upstream - > total_responses - upstream - > total_timeouts
2017-09-12 07:47:56 -05:00
- upstream - > conn_shutdowns * GETDNS_TRANSPORT_FAIL_MULT
- upstream - > conn_setup_failed ) ;
2016-06-23 09:53:51 -05:00
}
static int
upstream_valid ( getdns_upstream * upstream ,
getdns_transport_list_t transport ,
2017-09-12 07:47:56 -05:00
getdns_network_req * netreq ,
int backoff_ok )
2016-06-23 09:53:51 -05:00
{
2018-02-23 16:11:46 -06:00
/* Checking upstreams with backoff_ok true will also return upstreams
2017-09-13 04:00:56 -05:00
that are in a backoff state . Otherwise only use upstreams that have
2018-02-23 16:11:46 -06:00
a ' good ' connection state . backoff_ok is useful when no upstreams at all
2017-09-13 04:00:56 -05:00
are valid , for example when the network connection is down and need to
keep trying to connect before failing completely . */
2017-09-12 07:47:56 -05:00
if ( ! ( upstream - > transport = = transport & & upstream_usable ( upstream , backoff_ok ) ) )
2016-06-23 09:53:51 -05:00
return 0 ;
if ( transport = = GETDNS_TRANSPORT_TCP )
return 1 ;
2017-03-16 09:51:46 -05:00
if ( upstream - > conn_state = = GETDNS_CONN_OPEN ) {
if ( ! upstream_auth_status_ok ( upstream , netreq ) )
return 0 ;
else
return 1 ;
}
2016-06-23 09:53:51 -05:00
/* We need to check past authentication history to see if this is usable for TLS.*/
if ( netreq - > tls_auth_min ! = GETDNS_AUTHENTICATION_REQUIRED )
return 1 ;
2016-10-21 08:18:24 -05:00
return ( ( upstream - > best_tls_auth_state = = GETDNS_AUTH_OK | |
upstream - > best_tls_auth_state = = GETDNS_AUTH_NONE ) ? 1 : 0 ) ;
2016-06-23 09:53:51 -05:00
}
static int
upstream_valid_and_open ( getdns_upstream * upstream ,
2015-09-29 06:09:39 -05:00
getdns_transport_list_t transport ,
getdns_network_req * netreq )
2015-05-02 12:08:45 -05:00
{
2016-06-23 09:53:51 -05:00
if ( ! ( upstream - > transport = = transport & & upstream_active ( upstream ) ) )
2015-05-02 12:08:45 -05:00
return 0 ;
2016-06-23 09:53:51 -05:00
if ( transport = = GETDNS_TRANSPORT_TCP )
return 1 ;
/* Connection is complete, we know the auth status so check*/
if ( upstream - > conn_state = = GETDNS_CONN_OPEN & &
2016-07-14 04:42:21 -05:00
! upstream_auth_status_ok ( upstream , netreq ) )
2015-05-02 12:08:45 -05:00
return 0 ;
2016-06-23 09:53:51 -05:00
/* We must have a TLS connection still setting up so schedule and the
write code will check again once the connection is complete */
return 1 ;
2014-10-18 07:32:55 -05:00
}
2018-01-24 07:13:14 -06:00
static int
other_transports_working ( getdns_network_req * netreq ,
getdns_upstreams * upstreams ,
getdns_transport_list_t transport )
{
size_t i , j ;
for ( i = 0 ; i < netreq - > transport_count ; i + + ) {
if ( netreq - > transports [ i ] = = transport )
continue ;
if ( netreq - > transports [ i ] = = GETDNS_TRANSPORT_UDP ) {
for ( j = 0 ; j < upstreams - > count ; j + = GETDNS_UPSTREAM_TRANSPORTS ) {
if ( upstreams - > upstreams [ j ] . back_off = = 1 )
return 1 ;
}
}
else if ( netreq - > transports [ i ] = = GETDNS_TRANSPORT_TCP | |
netreq - > transports [ i ] = = GETDNS_TRANSPORT_TLS ) {
for ( j = 0 ; j < upstreams - > count ; j + + ) {
if ( netreq - > transports [ i ] = = upstreams - > upstreams [ j ] . transport & &
upstream_valid ( & upstreams - > upstreams [ j ] , netreq - > transports [ i ] ,
netreq , 0 ) )
return 1 ;
}
}
}
return 0 ;
}
2015-05-02 12:08:45 -05:00
static getdns_upstream *
2016-06-23 09:53:51 -05:00
upstream_select_stateful ( getdns_network_req * netreq , getdns_transport_list_t transport )
2015-04-19 11:16:58 -05:00
{
2016-06-23 09:53:51 -05:00
getdns_upstream * upstream = NULL ;
2015-05-02 12:08:45 -05:00
getdns_upstreams * upstreams = netreq - > owner - > upstreams ;
size_t i ;
2016-08-05 11:25:27 -05:00
time_t now = time ( NULL ) ;
2017-03-16 09:51:46 -05:00
2015-05-02 12:08:45 -05:00
if ( ! upstreams - > count )
return NULL ;
2016-06-23 09:53:51 -05:00
2016-08-05 11:25:27 -05:00
/* A check to re-instate backed-off upstreams after X amount of time*/
for ( i = 0 ; i < upstreams - > count ; i + + ) {
if ( upstreams - > upstreams [ i ] . conn_state = = GETDNS_CONN_BACKOFF & &
upstreams - > upstreams [ i ] . conn_retry_time < now ) {
upstreams - > upstreams [ i ] . conn_state = GETDNS_CONN_CLOSED ;
2017-09-12 09:01:02 -05:00
_getdns_upstream_log ( upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_NOTICE ,
2018-01-24 07:13:14 -06:00
" %-40s : Upstream : Re-instating %s for this upstream \n " ,
upstreams - > upstreams [ i ] . addr_str ,
upstreams - > upstreams [ i ] . transport = = GETDNS_TRANSPORT_TLS ? " TLS " : " TCP " ) ;
2016-08-05 11:25:27 -05:00
}
}
2016-06-23 09:53:51 -05:00
2017-03-17 11:53:03 -05:00
if ( netreq - > owner - > context - > round_robin_upstreams = = 0 ) {
2017-03-16 09:51:46 -05:00
/* First find if an open upstream has the correct properties and use that*/
for ( i = 0 ; i < upstreams - > count ; i + + ) {
if ( upstream_valid_and_open ( & upstreams - > upstreams [ i ] , transport , netreq ) )
return & upstreams - > upstreams [ i ] ;
}
2016-06-23 09:53:51 -05:00
}
2017-03-16 09:51:46 -05:00
/* OK - Find the next one to use. First check we have at least one valid
2018-01-24 07:13:14 -06:00
upstream ( not backed - off ) . Because we completely back off failed
2017-09-12 07:47:56 -05:00
upstreams we may have no valid upstream at all ( in contrast to UDP ) . */
2017-03-16 09:51:46 -05:00
i = upstreams - > current_stateful ;
do {
2018-01-24 07:13:14 -06:00
DEBUG_STUB ( " %s %-35s: Testing upstreams %d %d for transport %d \n " ,
STUB_DEBUG_SETUP , __FUNC__ , ( int ) i ,
( int ) upstreams - > upstreams [ i ] . conn_state , transport ) ;
2017-09-12 07:47:56 -05:00
if ( upstream_valid ( & upstreams - > upstreams [ i ] , transport , netreq , 0 ) ) {
2016-06-23 09:53:51 -05:00
upstream = & upstreams - > upstreams [ i ] ;
break ;
}
2017-03-16 09:51:46 -05:00
i + + ;
if ( i > = upstreams - > count )
i = 0 ;
} while ( i ! = upstreams - > current_stateful ) ;
2017-09-12 07:47:56 -05:00
if ( ! upstream ) {
2018-01-24 07:13:14 -06:00
/* Oh, oh. We have no valid upstreams for this transport. */
/* If there are other fallback transports that are working, we should
2018-02-08 05:02:48 -06:00
use them before forcibly promoting failed upstreams for re - try , since
waiting for the the re - try timer to re - instate them is the right thing
in this case . */
if ( other_transports_working ( netreq , upstreams , transport ) )
2017-09-12 07:47:56 -05:00
return NULL ;
2018-02-08 05:02:48 -06:00
/* Try to find one that might work so
allow backed off upstreams to be considered valid .
Don ' t worry about the policy , just use the one with the least bad
stats that still fits the bill ( right transport , right authentication )
to try to avoid total failure due to network outages . */
do {
if ( upstream_valid ( & upstreams - > upstreams [ i ] , transport , netreq , 1 ) ) {
upstream = & upstreams - > upstreams [ i ] ;
break ;
2018-01-24 07:13:14 -06:00
}
2018-02-08 05:02:48 -06:00
i + + ;
if ( i > = upstreams - > count )
i = 0 ;
} while ( i ! = upstreams - > current_stateful ) ;
if ( ! upstream ) {
/* We _really_ have nothing that authenticates well enough right now...
leave to regular backoff logic . */
return NULL ;
2018-01-24 07:13:14 -06:00
}
2018-02-08 05:02:48 -06:00
do {
i + + ;
if ( i > = upstreams - > count )
i = 0 ;
if ( upstream_valid ( & upstreams - > upstreams [ i ] , transport , netreq , 1 ) & &
upstream_stats ( & upstreams - > upstreams [ i ] ) > upstream_stats ( upstream ) )
upstream = & upstreams - > upstreams [ i ] ;
} while ( i ! = upstreams - > current_stateful ) ;
upstream - > conn_state = GETDNS_CONN_CLOSED ;
upstream - > conn_backoff_interval = 1 ;
_getdns_upstream_log ( upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_NOTICE ,
" %-40s : Upstream : No valid upstreams for %s... promoting this backed-off upstream for re-try... \n " ,
upstream - > addr_str ,
upstream - > transport = = GETDNS_TRANSPORT_TLS ? " TLS " : " TCP " ) ;
return upstream ;
2017-09-12 07:47:56 -05:00
}
2017-03-16 09:51:46 -05:00
/* Now select the specific upstream */
2017-03-17 11:53:03 -05:00
if ( netreq - > owner - > context - > round_robin_upstreams = = 0 ) {
2017-09-13 04:00:56 -05:00
/* Base the decision on the stats and being not backed-off,
noting we will have started from 0 */
2017-03-16 09:51:46 -05:00
for ( i + + ; i < upstreams - > count ; i + + ) {
2017-09-12 07:47:56 -05:00
if ( upstream_valid ( & upstreams - > upstreams [ i ] , transport , netreq , 0 ) & &
2017-03-16 09:51:46 -05:00
upstream_stats ( & upstreams - > upstreams [ i ] ) > upstream_stats ( upstream ) )
upstream = & upstreams - > upstreams [ i ] ;
}
} else {
/* Simplistic, but always just pick the first one, incrementing the current.
Note we are not distinguishing TCP / TLS here . . . . */
upstreams - > current_stateful + = GETDNS_UPSTREAM_TRANSPORTS ;
if ( upstreams - > current_stateful > = upstreams - > count )
upstreams - > current_stateful = 0 ;
2016-06-23 09:53:51 -05:00
}
2017-03-16 09:51:46 -05:00
2016-06-23 09:53:51 -05:00
return upstream ;
}
2018-02-26 09:46:57 -06:00
/* Used for UDP only */
2016-06-23 09:53:51 -05:00
static getdns_upstream *
upstream_select ( getdns_network_req * netreq )
{
getdns_upstream * upstream ;
getdns_upstreams * upstreams = netreq - > owner - > upstreams ;
size_t i ;
if ( ! upstreams - > count )
return NULL ;
2018-02-26 09:46:57 -06:00
2016-06-23 09:53:51 -05:00
/* First UPD/TCP upstream is always at i=0 and then start of each upstream block*/
/* TODO: Have direct access to sets of upstreams for different transports*/
for ( i = 0 ; i < upstreams - > count ; i + = GETDNS_UPSTREAM_TRANSPORTS )
2015-05-02 12:08:45 -05:00
if ( upstreams - > upstreams [ i ] . to_retry < = 0 )
upstreams - > upstreams [ i ] . to_retry + + ;
2014-12-07 13:03:34 -06:00
2016-06-23 09:53:51 -05:00
i = upstreams - > current_udp ;
2015-05-02 12:08:45 -05:00
do {
2016-06-23 09:53:51 -05:00
if ( upstreams - > upstreams [ i ] . to_retry > 0 ) {
upstreams - > current_udp = i ;
2015-05-02 12:08:45 -05:00
return & upstreams - > upstreams [ i ] ;
2014-12-07 13:03:34 -06:00
}
2016-06-23 09:53:51 -05:00
i + = GETDNS_UPSTREAM_TRANSPORTS ;
2017-07-31 16:51:24 -05:00
if ( i > = upstreams - > count )
2015-05-02 12:08:45 -05:00
i = 0 ;
2016-06-23 09:53:51 -05:00
} while ( i ! = upstreams - > current_udp ) ;
2015-05-02 12:08:45 -05:00
2018-02-26 09:46:57 -06:00
/* Select upstream with the lowest back_off value */
2015-05-02 12:08:45 -05:00
upstream = upstreams - > upstreams ;
2016-06-23 09:53:51 -05:00
for ( i = 0 ; i < upstreams - > count ; i + = GETDNS_UPSTREAM_TRANSPORTS )
2018-02-26 09:46:57 -06:00
if ( upstreams - > upstreams [ i ] . back_off < upstream - > back_off )
2015-05-02 12:08:45 -05:00
upstream = & upstreams - > upstreams [ i ] ;
2018-02-26 09:46:57 -06:00
/* Restrict back_off in case no upstream is available to achieve
( more or less ) round - robin retry on all upstreams . */
if ( upstream - > back_off > 4 )
for ( i = 0 ; i < upstreams - > count ; i + = GETDNS_UPSTREAM_TRANSPORTS )
upstreams - > upstreams [ i ] . back_off = 2 ;
2015-05-02 12:08:45 -05:00
upstream - > to_retry = 1 ;
2017-03-22 04:52:55 -05:00
upstreams - > current_udp = upstream - upstreams - > upstreams ;
2015-05-02 12:08:45 -05:00
return upstream ;
2014-12-07 13:03:34 -06:00
}
2015-04-19 11:16:58 -05:00
int
2015-06-19 12:28:29 -05:00
upstream_connect ( getdns_upstream * upstream , getdns_transport_list_t transport ,
2015-04-29 13:20:25 -05:00
getdns_dns_req * dnsreq )
2015-04-19 11:16:58 -05:00
{
2016-06-23 09:53:51 -05:00
DEBUG_STUB ( " %s %-35s: Getting upstream connection: %p \n " , STUB_DEBUG_SETUP ,
2016-12-12 07:20:31 -06:00
__FUNC__ , ( void * ) upstream ) ;
2015-04-24 10:29:08 -05:00
int fd = - 1 ;
2015-04-19 11:16:58 -05:00
switch ( transport ) {
2015-06-19 12:28:29 -05:00
case GETDNS_TRANSPORT_UDP :
2015-04-19 11:16:58 -05:00
if ( ( fd = socket (
upstream - > addr . ss_family , SOCK_DGRAM , IPPROTO_UDP ) ) = = - 1 )
return - 1 ;
getdns_sock_nonblock ( fd ) ;
2016-06-23 09:53:51 -05:00
break ;
2015-04-19 11:16:58 -05:00
2015-06-19 12:28:29 -05:00
case GETDNS_TRANSPORT_TCP :
case GETDNS_TRANSPORT_TLS :
2015-04-30 06:24:13 -05:00
/* Use existing if available*/
2016-06-23 09:53:51 -05:00
if ( upstream - > fd ! = - 1 )
2015-04-30 06:24:13 -05:00
return upstream - > fd ;
2015-04-19 11:16:58 -05:00
fd = tcp_connect ( upstream , transport ) ;
2016-06-23 09:53:51 -05:00
if ( fd = = - 1 ) {
upstream_failed ( upstream , 1 ) ;
2015-04-19 11:16:58 -05:00
return - 1 ;
}
2016-04-11 07:49:44 -05:00
upstream - > loop = dnsreq - > loop ;
upstream - > is_sync_loop = dnsreq - > is_sync_request ;
2015-04-29 13:20:25 -05:00
upstream - > fd = fd ;
2016-06-23 09:53:51 -05:00
if ( transport = = GETDNS_TRANSPORT_TLS ) {
upstream - > tls_obj = tls_create_object ( dnsreq , fd , upstream ) ;
if ( upstream - > tls_obj = = NULL ) {
upstream_failed ( upstream , 1 ) ;
2017-10-04 11:31:33 -05:00
_getdns_closesocket ( fd ) ;
2016-06-23 09:53:51 -05:00
return - 1 ;
}
upstream - > tls_hs_state = GETDNS_HS_WRITE ;
}
upstream - > conn_state = GETDNS_CONN_SETUP ;
2017-06-28 13:57:53 -05:00
_getdns_upstream_log ( upstream , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_DEBUG ,
2017-07-06 00:43:31 -05:00
" %-40s : Conn opened: %s - %s Profile \n " ,
2017-06-26 17:23:22 -05:00
upstream - > addr_str , transport = = GETDNS_TRANSPORT_TLS ? " TLS " : " TCP " ,
dnsreq - > context - > tls_auth_min = = GETDNS_AUTHENTICATION_NONE ? " Opportunistic " : " Strict " ) ;
2015-04-29 13:20:25 -05:00
break ;
2015-04-19 11:16:58 -05:00
default :
return - 1 ;
/* Nothing to do*/
}
return fd ;
}
2015-04-29 13:20:25 -05:00
static getdns_upstream *
2016-03-01 12:05:01 -06:00
upstream_find_for_transport ( getdns_network_req * netreq ,
2016-06-23 09:53:51 -05:00
getdns_transport_list_t transport ,
int * fd )
2015-04-29 13:20:25 -05:00
{
2016-06-23 09:53:51 -05:00
getdns_upstream * upstream = NULL ;
2016-08-08 10:12:33 -05:00
/* UDP always returns an upstream, the only reason this will fail is if
no socket is available , in which case that is an error . */
2016-06-23 09:53:51 -05:00
if ( transport = = GETDNS_TRANSPORT_UDP ) {
upstream = upstream_select ( netreq ) ;
2016-08-08 10:12:33 -05:00
* fd = upstream_connect ( upstream , transport , netreq - > owner ) ;
return upstream ;
2016-06-23 09:53:51 -05:00
}
2016-08-08 10:12:33 -05:00
else {
/* For stateful transport we should keep trying until all our transports
2017-09-12 07:47:56 -05:00
are exhausted / backed - off ( no upstream ) and until we have tried each
upstream at least once for this netreq in a total backoff scenario */
size_t i = 0 ;
2016-08-08 10:12:33 -05:00
do {
upstream = upstream_select_stateful ( netreq , transport ) ;
if ( ! upstream )
return NULL ;
* fd = upstream_connect ( upstream , transport , netreq - > owner ) ;
2017-09-12 07:47:56 -05:00
if ( i > = upstream - > upstreams - > count )
return NULL ;
i + + ;
2016-08-08 10:12:33 -05:00
} while ( * fd = = - 1 ) ;
DEBUG_STUB ( " %s %-35s: FD: %d Connecting to upstream: %p No: %d \n " ,
2016-12-12 07:20:31 -06:00
STUB_DEBUG_SETUP , __FUNC__ , * fd , ( void * ) upstream ,
2016-06-23 09:53:51 -05:00
( int ) ( upstream - netreq - > owner - > context - > upstreams - > upstreams ) ) ;
2016-08-08 10:12:33 -05:00
}
2015-04-29 13:20:25 -05:00
return upstream ;
}
static int
2016-03-01 12:05:01 -06:00
upstream_find_for_netreq ( getdns_network_req * netreq )
2014-10-15 16:57:24 -05:00
{
2015-04-24 10:29:08 -05:00
int fd = - 1 ;
2015-06-22 12:02:28 -05:00
getdns_upstream * upstream ;
2017-09-01 09:23:26 -05:00
size_t i ;
for ( i = netreq - > transport_current ;
i < netreq - > transport_count ; i + + ) {
2016-03-01 12:05:01 -06:00
upstream = upstream_find_for_transport ( netreq ,
2015-06-19 12:28:29 -05:00
netreq - > transports [ i ] ,
2015-04-29 13:20:25 -05:00
& fd ) ;
2017-03-20 09:20:17 -05:00
if ( ! upstream )
2015-10-16 12:31:57 -05:00
continue ;
2017-03-20 09:20:17 -05:00
if ( fd = = - 1 ) {
2017-11-03 10:42:38 -05:00
if ( _getdns_resource_depletion ( ) )
2017-03-20 09:20:17 -05:00
return STUB_TRY_AGAIN_LATER ;
return - 1 ;
}
2018-03-02 08:56:00 -06:00
if ( upstream = = netreq - > first_upstream )
continue ;
2015-06-19 12:28:29 -05:00
netreq - > transport_current = i ;
2015-06-22 12:02:28 -05:00
netreq - > upstream = upstream ;
2018-03-02 08:56:00 -06:00
if ( ! netreq - > first_upstream )
netreq - > first_upstream = upstream ;
2015-11-24 11:59:01 -06:00
netreq - > keepalive_sent = 0 ;
2017-06-15 10:21:05 -05:00
DEBUG_STUB ( " %s %-35s: MSG: %p found upstream %p with transport %d, fd: %d \n " , STUB_DEBUG_SCHEDULE , __FUNC__ , ( void * ) netreq , ( void * ) upstream , ( int ) netreq - > transports [ i ] , fd ) ;
2015-04-29 13:20:25 -05:00
return fd ;
}
2016-06-23 09:53:51 -05:00
/* Handle better, will give generic error*/
2016-12-12 07:20:31 -06:00
DEBUG_STUB ( " %s %-35s: MSG: %p No valid upstream! \n " , STUB_DEBUG_SCHEDULE , __FUNC__ , ( void * ) netreq ) ;
2017-09-12 09:01:02 -05:00
_getdns_context_log ( netreq - > owner - > context , GETDNS_LOG_UPSTREAM_STATS , GETDNS_LOG_ERR ,
2018-01-24 07:13:14 -06:00
" *FAILURE* no valid transports or upstreams available! \n " ) ;
2015-04-29 13:20:25 -05:00
return - 1 ;
}
2015-05-02 12:08:45 -05:00
/************************/
/* Scheduling functions */
/***********************/
2015-04-29 13:20:25 -05:00
static int
2015-06-22 12:02:28 -05:00
fallback_on_write ( getdns_network_req * netreq )
2015-04-29 13:20:25 -05:00
{
2017-03-13 08:20:47 -05:00
uint64_t now_ms = 0 ;
2015-04-29 13:20:25 -05:00
2016-06-23 09:53:51 -05:00
/* Deal with UDP one day*/
2016-12-12 07:20:31 -06:00
DEBUG_STUB ( " %s %-35s: MSG: %p FALLING BACK \n " , STUB_DEBUG_SCHEDULE , __FUNC__ , ( void * ) netreq ) ;
2015-04-29 13:20:25 -05:00
2015-06-25 14:21:00 -05:00
/* Try to find a fallback transport*/
2017-03-13 08:20:47 -05:00
getdns_return_t result = _getdns_submit_stub_request ( netreq , & now_ms ) ;
2015-04-29 13:20:25 -05:00
2015-06-25 14:21:00 -05:00
if ( result ! = GETDNS_RETURN_GOOD )
return STUB_TCP_ERROR ;
2015-06-24 12:49:34 -05:00
return ( netreq - > transports [ netreq - > transport_current ]
= = GETDNS_TRANSPORT_UDP ) ?
2015-06-22 12:02:28 -05:00
netreq - > fd : netreq - > upstream - > fd ;
2015-04-29 13:20:25 -05:00
}
2015-06-24 12:49:34 -05:00
static void
2017-10-17 06:47:29 -05:00
upstream_reschedule_events ( getdns_upstream * upstream ) {
2015-06-24 12:49:34 -05:00
2016-03-18 07:02:40 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d \n " , STUB_DEBUG_SCHEDULE ,
2016-12-12 06:55:10 -06:00
__FUNC__ , upstream - > fd ) ;
2017-10-17 09:58:01 -05:00
if ( upstream - > event . ev )
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
if ( upstream - > fd = = - 1 | | ! ( upstream - > conn_state = = GETDNS_CONN_SETUP
| | upstream - > conn_state = = GETDNS_CONN_OPEN ) )
return ;
2015-06-24 12:49:34 -05:00
if ( ! upstream - > write_queue & & upstream - > event . write_cb ) {
upstream - > event . write_cb = NULL ;
}
2015-06-25 14:21:00 -05:00
if ( upstream - > write_queue & & ! upstream - > event . write_cb ) {
upstream - > event . write_cb = upstream_write_cb ;
}
2015-06-24 12:49:34 -05:00
if ( ! upstream - > netreq_by_query_id . count & & upstream - > event . read_cb ) {
upstream - > event . read_cb = NULL ;
}
2015-06-25 14:21:00 -05:00
if ( upstream - > netreq_by_query_id . count & & ! upstream - > event . read_cb ) {
upstream - > event . read_cb = upstream_read_cb ;
}
2015-08-17 05:35:10 -05:00
if ( upstream - > event . read_cb | | upstream - > event . write_cb )
GETDNS_SCHEDULE_EVENT ( upstream - > loop ,
upstream - > fd , TIMEOUT_FOREVER , & upstream - > event ) ;
else {
2016-06-15 11:05:58 -05:00
DEBUG_STUB ( " %s %-35s: FD: %d Connection idle - timeout is %d \n " ,
2017-10-17 06:47:29 -05:00
STUB_DEBUG_SCHEDULE , __FUNC__ , upstream - > fd ,
( int ) upstream - > keepalive_timeout ) ;
2017-10-17 09:58:01 -05:00
upstream - > event . read_cb = upstream_read_cb ;
2015-08-17 05:35:10 -05:00
upstream - > event . timeout_cb = upstream_idle_timeout_cb ;
2017-10-17 09:58:01 -05:00
GETDNS_SCHEDULE_EVENT ( upstream - > loop , upstream - > fd ,
upstream - > keepalive_timeout , & upstream - > event ) ;
2015-04-19 11:16:58 -05:00
}
2015-04-29 13:20:25 -05:00
}
2015-05-02 12:08:45 -05:00
static void
upstream_schedule_netreq ( getdns_upstream * upstream , getdns_network_req * netreq )
{
2016-12-12 07:20:31 -06:00
DEBUG_STUB ( " %s %-35s: MSG: %p (schedule event) \n " , STUB_DEBUG_SCHEDULE , __FUNC__ , ( void * ) netreq ) ;
2015-05-02 12:08:45 -05:00
/* We have a connected socket and a global event loop */
assert ( upstream - > fd > = 0 ) ;
assert ( upstream - > loop ) ;
/* Append netreq to write_queue */
if ( ! upstream - > write_queue ) {
upstream - > write_queue = upstream - > write_queue_last = netreq ;
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
2016-04-11 07:49:44 -05:00
if ( netreq - > owner - > is_sync_request & & ! upstream - > is_sync_loop ) {
/* An initial synchronous call, change loop */
upstream - > loop = netreq - > owner - > loop ;
upstream - > is_sync_loop = 1 ;
}
2015-07-14 04:54:25 -05:00
upstream - > event . timeout_cb = NULL ;
2015-06-23 09:39:56 -05:00
upstream - > event . write_cb = upstream_write_cb ;
2016-06-23 09:53:51 -05:00
if ( upstream - > queries_sent = = 0 ) {
2015-05-03 09:11:46 -05:00
/* Set a timeout on the upstream so we can catch failed setup*/
2016-06-23 09:53:51 -05:00
upstream - > event . timeout_cb = upstream_setup_timeout_cb ;
2017-03-13 08:20:47 -05:00
GETDNS_SCHEDULE_EVENT ( upstream - > loop , upstream - > fd ,
_getdns_ms_until_expiry ( netreq - > owner - > expires ) / 2 ,
2015-06-23 09:39:56 -05:00
& upstream - > event ) ;
2015-05-03 09:11:46 -05:00
} else {
GETDNS_SCHEDULE_EVENT ( upstream - > loop ,
upstream - > fd , TIMEOUT_FOREVER , & upstream - > event ) ;
}
2016-04-11 07:49:44 -05:00
} else if ( netreq - > owner - > is_sync_request & & ! upstream - > is_sync_loop ) {
/* Initial synchronous call on an upstream in use,
* prioritize this request ( insert at 0 )
* and reschedule against synchronous loop .
*/
2016-03-23 16:13:31 -05:00
netreq - > write_queue_tail = upstream - > write_queue ;
upstream - > write_queue = netreq ;
2016-04-11 07:49:44 -05:00
GETDNS_CLEAR_EVENT ( upstream - > loop , & upstream - > event ) ;
upstream - > loop = netreq - > owner - > loop ;
upstream - > is_sync_loop = 1 ;
GETDNS_SCHEDULE_EVENT ( upstream - > loop , upstream - > fd ,
TIMEOUT_FOREVER , & upstream - > event ) ;
2015-05-02 12:08:45 -05:00
} else {
2016-04-11 07:49:44 -05:00
/* "Follow-up synchronous" or Asynchronous call,
* this request comes last ( append )
*/
2015-05-02 12:08:45 -05:00
upstream - > write_queue_last - > write_queue_tail = netreq ;
upstream - > write_queue_last = netreq ;
}
}
2015-04-29 13:20:25 -05:00
getdns_return_t
2017-03-13 08:20:47 -05:00
_getdns_submit_stub_request ( getdns_network_req * netreq , uint64_t * now_ms )
2015-04-29 13:20:25 -05:00
{
2017-03-20 09:20:17 -05:00
int fd = - 1 ;
getdns_dns_req * dnsreq ;
getdns_context * context ;
2016-12-12 06:55:10 -06:00
DEBUG_STUB ( " %s %-35s: MSG: %p TYPE: %d \n " , STUB_DEBUG_ENTRY , __FUNC__ ,
2016-12-09 11:15:28 -06:00
( void * ) netreq , netreq - > request_type ) ;
2017-03-20 09:20:17 -05:00
dnsreq = netreq - > owner ;
context = dnsreq - > context ;
2015-04-29 13:20:25 -05:00
/* This does a best effort to get a initial fd.
* All other set up is done async */
2016-03-01 12:05:01 -06:00
fd = upstream_find_for_netreq ( netreq ) ;
2015-04-24 10:29:08 -05:00
if ( fd = = - 1 )
2017-02-23 08:49:17 -06:00
return GETDNS_RETURN_NO_UPSTREAM_AVAILABLE ;
2014-10-17 17:25:41 -05:00
2017-03-20 09:20:17 -05:00
else if ( fd = = STUB_TRY_AGAIN_LATER ) {
_getdns_netreq_change_state ( netreq , NET_REQ_NOT_SENT ) ;
netreq - > node . key = netreq ;
if ( _getdns_rbtree_insert (
& context - > pending_netreqs , & netreq - > node ) )
return GETDNS_RETURN_GOOD ;
return GETDNS_RETURN_NO_UPSTREAM_AVAILABLE ;
}
switch ( netreq - > transports [ netreq - > transport_current ] ) {
2015-06-19 12:28:29 -05:00
case GETDNS_TRANSPORT_UDP :
2015-04-19 11:16:58 -05:00
netreq - > fd = fd ;
2015-06-24 12:49:34 -05:00
GETDNS_CLEAR_EVENT ( dnsreq - > loop , & netreq - > event ) ;
2017-03-13 08:20:47 -05:00
GETDNS_SCHEDULE_EVENT ( dnsreq - > loop , netreq - > fd ,
_getdns_ms_until_expiry2 ( dnsreq - > expires , now_ms ) ,
2014-10-17 17:25:41 -05:00
getdns_eventloop_event_init ( & netreq - > event , netreq ,
2015-11-24 11:59:01 -06:00
NULL , stub_udp_write_cb , stub_timeout_cb ) ) ;
2014-10-17 17:25:41 -05:00
return GETDNS_RETURN_GOOD ;
2015-12-17 11:20:08 -06:00
2016-03-17 10:49:05 -05:00
case GETDNS_TRANSPORT_TLS :
2016-03-18 07:30:49 -05:00
case GETDNS_TRANSPORT_TCP :
2015-04-29 13:20:25 -05:00
upstream_schedule_netreq ( netreq - > upstream , netreq ) ;
2015-08-11 12:34:32 -05:00
/* For TLS, set a short timeout to catch setup problems. This is reset
when the connection is successful . */
2015-06-22 12:02:28 -05:00
GETDNS_CLEAR_EVENT ( dnsreq - > loop , & netreq - > event ) ;
2015-10-31 03:15:36 -05:00
/*************************************************************
* * * * * * * * * * *
2016-03-23 16:13:31 -05:00
* * * * * * Scheduling differences of * * * * *
* * * * * * synchronous and asynchronous requests * * * * *
2015-10-31 03:15:36 -05:00
* * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
2016-03-23 16:13:31 -05:00
* Besides the asynchronous event loop , which is typically
* shared with the application , every getdns context also
* has another event loop ( not registered by the user ) which
* is used specifically and only for synchronous requests :
* context - > sync_eventloop .
2015-10-31 03:15:36 -05:00
*
2016-03-23 16:13:31 -05:00
* We do not use the asynchronous loop for the duration of the
2015-10-31 04:24:24 -05:00
* synchronous query , because :
* - Callbacks for outstanding ( and thus asynchronous ) queries
* might fire as a side effect .
2016-03-23 16:13:31 -05:00
* - But worse , since the asynchronous loop is created and
* managed by the user , which may well have her own non - dns
* related events scheduled against it , they will fire as
* well as a side effect of doing the synchronous request !
*
2015-10-31 03:15:36 -05:00
*
* Transports that keep connections open , have their own event
2015-10-31 04:24:24 -05:00
* structure to keep their connection state . The event is
* associated with the upstream struct . Note that there is a
2016-03-23 16:13:31 -05:00
* separate upstream struct for each state full transport , so
2015-10-31 04:24:24 -05:00
* each upstream has multiple transport structs !
*
* side note : The upstream structs have their own reference
* to the " context's " event loop so they can ,
* in theory , be detached ( to finish running
* queries for example ) .
2015-10-31 03:15:36 -05:00
*
* If a synchronous request is scheduled for such a transport ,
2015-10-31 04:24:24 -05:00
* then the sync - loop temporarily has to " run " that
* upstream / transport ' s event ! Outstanding requests for that
2016-03-23 16:13:31 -05:00
* upstream / transport might come in while processing the
* synchronous call . When this happens , they are queued up
* ( at upstream - > finished_queue ) and an timeout event of 1
* will be scheduled against the asynchronous loop to start
* processing those received request as soon as the
* asynchronous loop will be run .
2015-10-31 04:24:24 -05:00
*
2015-10-31 03:15:36 -05:00
*
2016-03-23 16:13:31 -05:00
* When getdns is linked with libunbound 1.5 .8 or older , then
* when a RECURSING synchronous request is made then
* outstanding asynchronously scheduled RECURSING requests
2015-10-31 04:24:24 -05:00
* may fire as a side effect , as we reuse the same code path
2016-03-23 16:13:31 -05:00
* For both synchronous and asynchronous calls ,
* ub_resolve_async ( ) is used under the hood .
*
* With libunbound versions newer than 1.5 .8 , libunbound will
* share the event loops used with getdns which will prevent
* these side effects from happening .
2015-10-31 03:15:36 -05:00
*
*
2016-03-23 16:13:31 -05:00
* The event loop used for a specific request is in
* dnsreq - > loop . The asynchronous is always also available
* at the upstream as upstream - > loop .
2015-10-31 03:15:36 -05:00
*/
2016-03-18 07:30:49 -05:00
GETDNS_SCHEDULE_EVENT (
2016-04-11 07:49:44 -05:00
dnsreq - > loop , - 1 ,
2017-03-13 08:20:47 -05:00
_getdns_ms_until_expiry2 ( dnsreq - > expires , now_ms ) ,
2016-04-11 07:49:44 -05:00
getdns_eventloop_event_init (
& netreq - > event , netreq , NULL , NULL ,
2016-06-23 09:53:51 -05:00
stub_timeout_cb ) ) ;
2016-03-18 07:30:49 -05:00
2014-10-18 07:32:55 -05:00
return GETDNS_RETURN_GOOD ;
2014-10-17 17:25:41 -05:00
default :
return GETDNS_RETURN_GENERIC_ERROR ;
}
2014-09-16 08:43:20 -05:00
}
2015-05-13 05:47:17 -05:00
/* stub.c */