2014-05-07 22:27:00 +00:00
/*
2018-04-11 14:24:29 +00:00
Copyright ( c ) 2009 - 2018 Roger Light < roger @ atchoo . org >
2014-05-07 22:27:00 +00:00
All rights reserved . This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1 .0
and Eclipse Distribution License v1 .0 which accompany this distribution .
2018-02-13 14:16:47 +00:00
2014-05-07 22:27:00 +00:00
The Eclipse Public License is available at
http : //www.eclipse.org/legal/epl-v10.html
and the Eclipse Distribution License is available at
http : //www.eclipse.org/org/documents/edl-v10.php.
2018-02-13 14:16:47 +00:00
2014-05-07 22:27:00 +00:00
Contributors :
Roger Light - initial implementation and documentation .
*/
2017-02-06 22:39:39 +00:00
# define _GNU_SOURCE
2018-08-15 16:02:56 +00:00
# include "config.h"
2017-02-06 22:39:39 +00:00
2014-05-07 22:27:00 +00:00
# include <assert.h>
# include <errno.h>
# include <fcntl.h>
# include <stdio.h>
# include <string.h>
# ifndef WIN32
2017-02-06 22:39:39 +00:00
# define _GNU_SOURCE
2014-05-07 22:27:00 +00:00
# include <netdb.h>
# include <sys/socket.h>
# include <unistd.h>
# else
# include <winsock2.h>
# include <ws2tcpip.h>
# endif
2014-11-12 20:47:16 +00:00
# ifdef __ANDROID__
2014-05-07 22:27:00 +00:00
# include <linux/in.h>
# include <linux/in6.h>
# include <sys/endian.h>
# endif
2018-08-09 14:21:40 +00:00
# ifdef HAVE_NETINET_IN_H
2014-05-07 22:27:00 +00:00
# include <netinet / in.h>
# endif
# ifdef __QNX__
# include <net/netbyte.h>
# endif
# ifdef WITH_TLS
2014-06-28 00:38:58 +00:00
# include <openssl/conf.h>
# include <openssl/engine.h>
2014-05-07 22:27:00 +00:00
# include <openssl/err.h>
# include <tls_mosq.h>
# endif
# ifdef WITH_BROKER
2016-07-08 09:10:04 +00:00
# include "mosquitto_broker_internal.h"
2014-05-06 09:47:00 +00:00
# ifdef WITH_WEBSOCKETS
# include <libwebsockets.h>
# endif
2014-05-07 22:27:00 +00:00
# else
2015-04-29 20:37:47 +00:00
# include "read_handle.h"
2014-05-07 22:27:00 +00:00
# endif
2015-04-29 20:37:47 +00:00
# include "logging_mosq.h"
# include "memory_mosq.h"
# include "mqtt3_protocol.h"
# include "net_mosq.h"
# include "time_mosq.h"
# include "util_mosq.h"
2014-05-07 22:27:00 +00:00
# ifdef WITH_TLS
int tls_ex_index_mosq = - 1 ;
# endif
2015-09-22 09:03:57 +00:00
int net__init ( void )
2014-05-07 22:27:00 +00:00
{
# ifdef WIN32
WSADATA wsaData ;
2015-09-22 09:03:57 +00:00
if ( WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsaData ) ! = 0 ) {
return MOSQ_ERR_UNKNOWN ;
}
2014-05-07 22:27:00 +00:00
# endif
# ifdef WITH_SRV
ares_library_init ( ARES_LIB_INIT_ALL ) ;
# endif
# ifdef WITH_TLS
SSL_load_error_strings ( ) ;
SSL_library_init ( ) ;
OpenSSL_add_all_algorithms ( ) ;
if ( tls_ex_index_mosq = = - 1 ) {
tls_ex_index_mosq = SSL_get_ex_new_index ( 0 , " client context " , NULL , NULL , NULL ) ;
}
# endif
2015-09-22 09:03:57 +00:00
return MOSQ_ERR_SUCCESS ;
2014-05-07 22:27:00 +00:00
}
2015-05-18 08:29:22 +00:00
void net__cleanup ( void )
2014-05-07 22:27:00 +00:00
{
# ifdef WITH_TLS
2017-04-03 19:45:42 +00:00
# if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_remove_state ( 0 ) ;
# endif
2018-08-24 09:45:51 +00:00
# ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup ( ) ;
# endif
2014-06-28 00:38:58 +00:00
CONF_modules_unload ( 1 ) ;
2014-05-07 22:27:00 +00:00
ERR_free_strings ( ) ;
EVP_cleanup ( ) ;
CRYPTO_cleanup_all_ex_data ( ) ;
# endif
# ifdef WITH_SRV
ares_library_cleanup ( ) ;
# endif
# ifdef WIN32
WSACleanup ( ) ;
# endif
}
/* Close a socket associated with a context and set it to -1.
* Returns 1 on failure ( context is NULL )
* Returns 0 on success .
*/
2014-06-23 16:57:35 +00:00
# ifdef WITH_BROKER
2015-05-18 08:29:22 +00:00
int net__socket_close ( struct mosquitto_db * db , struct mosquitto * mosq )
2014-06-23 16:57:35 +00:00
# else
2015-05-18 08:29:22 +00:00
int net__socket_close ( struct mosquitto * mosq )
2014-06-23 16:57:35 +00:00
# endif
2014-05-07 22:27:00 +00:00
{
int rc = 0 ;
assert ( mosq ) ;
# ifdef WITH_TLS
2017-07-26 23:12:32 +00:00
# ifdef WITH_WEBSOCKETS
if ( ! mosq - > wsi )
# endif
{
if ( mosq - > ssl ) {
SSL_shutdown ( mosq - > ssl ) ;
SSL_free ( mosq - > ssl ) ;
mosq - > ssl = NULL ;
}
if ( mosq - > ssl_ctx ) {
SSL_CTX_free ( mosq - > ssl_ctx ) ;
mosq - > ssl_ctx = NULL ;
}
2014-05-07 22:27:00 +00:00
}
# endif
2014-06-29 22:16:10 +00:00
# ifdef WITH_WEBSOCKETS
2017-07-27 13:56:10 +00:00
if ( mosq - > wsi )
{
2014-06-29 22:16:10 +00:00
if ( mosq - > state ! = mosq_cs_disconnecting ) {
mosq - > state = mosq_cs_disconnect_ws ;
}
2017-07-27 13:56:10 +00:00
libwebsocket_callback_on_writable ( mosq - > ws_context , mosq - > wsi ) ;
} else
2014-06-29 22:16:10 +00:00
# endif
2017-07-27 13:56:10 +00:00
{
if ( ( int ) mosq - > sock > = 0 ) {
# ifdef WITH_BROKER
HASH_DELETE ( hh_sock , db - > contexts_by_sock , mosq ) ;
# endif
rc = COMPAT_CLOSE ( mosq - > sock ) ;
mosq - > sock = INVALID_SOCKET ;
}
2014-05-07 22:27:00 +00:00
}
2014-06-03 15:21:46 +00:00
# ifdef WITH_BROKER
if ( mosq - > listener ) {
mosq - > listener - > client_count - - ;
assert ( mosq - > listener - > client_count > = 0 ) ;
mosq - > listener = NULL ;
}
# endif
2014-05-07 22:27:00 +00:00
return rc ;
}
2015-04-29 20:23:59 +00:00
2018-04-11 16:10:27 +00:00
# ifdef WITH_TLS_PSK
2014-05-07 22:27:00 +00:00
static unsigned int psk_client_callback ( SSL * ssl , const char * hint ,
char * identity , unsigned int max_identity_len ,
unsigned char * psk , unsigned int max_psk_len )
{
struct mosquitto * mosq ;
int len ;
mosq = SSL_get_ex_data ( ssl , tls_ex_index_mosq ) ;
if ( ! mosq ) return 0 ;
snprintf ( identity , max_identity_len , " %s " , mosq - > tls_psk_identity ) ;
2015-04-19 21:10:59 +00:00
len = mosquitto__hex2bin ( mosq - > tls_psk , psk , max_psk_len ) ;
2014-05-07 22:27:00 +00:00
if ( len < 0 ) return 0 ;
return len ;
}
# endif
2017-02-08 22:30:00 +00:00
# if defined(WITH_BROKER) && defined(__GLIBC__) && defined(WITH_ADNS)
2017-02-06 22:39:39 +00:00
/* Async connect, part 1 (dns lookup) */
2017-03-06 21:19:53 +00:00
int net__try_connect_step1 ( struct mosquitto * mosq , const char * host )
2017-02-06 22:39:39 +00:00
{
int s ;
void * sevp = NULL ;
2018-12-04 12:39:00 +00:00
struct addrinfo * hints ;
2017-02-06 22:39:39 +00:00
if ( mosq - > adns ) {
2018-12-04 12:39:00 +00:00
gai_cancel ( mosq - > adns ) ;
mosquitto__free ( ( struct addrinfo * ) mosq - > adns - > ar_request ) ;
2017-03-06 21:19:53 +00:00
mosquitto__free ( mosq - > adns ) ;
2017-02-06 22:39:39 +00:00
}
2017-03-06 21:19:53 +00:00
mosq - > adns = mosquitto__calloc ( 1 , sizeof ( struct gaicb ) ) ;
2017-02-06 22:39:39 +00:00
if ( ! mosq - > adns ) {
return MOSQ_ERR_NOMEM ;
}
2018-12-04 12:39:00 +00:00
hints = mosquitto__calloc ( 1 , sizeof ( struct addrinfo ) ) ;
if ( ! hints ) {
mosquitto__free ( mosq - > adns ) ;
mosq - > adns = NULL ;
return MOSQ_ERR_NOMEM ;
}
hints - > ai_family = AF_UNSPEC ;
hints - > ai_socktype = SOCK_STREAM ;
2017-02-06 22:39:39 +00:00
mosq - > adns - > ar_name = host ;
2018-12-04 12:39:00 +00:00
mosq - > adns - > ar_request = hints ;
2017-02-06 22:39:39 +00:00
s = getaddrinfo_a ( GAI_NOWAIT , & mosq - > adns , 1 , sevp ) ;
if ( s ) {
errno = s ;
2018-12-04 12:39:00 +00:00
if ( mosq - > adns ) {
mosquitto__free ( ( struct addrinfo * ) mosq - > adns - > ar_request ) ;
mosquitto__free ( mosq - > adns ) ;
mosq - > adns = NULL ;
}
2017-02-06 22:39:39 +00:00
return MOSQ_ERR_EAI ;
}
return MOSQ_ERR_SUCCESS ;
}
/* Async connect part 2, the connection. */
2017-03-06 21:19:53 +00:00
int net__try_connect_step2 ( struct mosquitto * mosq , uint16_t port , mosq_sock_t * sock )
2017-02-06 22:39:39 +00:00
{
struct addrinfo * ainfo , * rp ;
int rc ;
ainfo = mosq - > adns - > ar_result ;
for ( rp = ainfo ; rp ! = NULL ; rp = rp - > ai_next ) {
* sock = socket ( rp - > ai_family , rp - > ai_socktype , rp - > ai_protocol ) ;
if ( * sock = = INVALID_SOCKET ) continue ;
2018-08-01 23:27:52 +00:00
if ( rp - > ai_family = = AF_INET ) {
2017-02-06 22:39:39 +00:00
( ( struct sockaddr_in * ) rp - > ai_addr ) - > sin_port = htons ( port ) ;
2018-08-01 23:27:52 +00:00
} else if ( rp - > ai_family = = AF_INET6 ) {
2017-02-06 22:39:39 +00:00
( ( struct sockaddr_in6 * ) rp - > ai_addr ) - > sin6_port = htons ( port ) ;
} else {
COMPAT_CLOSE ( * sock ) ;
2018-08-08 14:23:03 +00:00
* sock = INVALID_SOCKET ;
2017-02-06 22:39:39 +00:00
continue ;
}
/* Set non-blocking */
2018-08-08 14:23:03 +00:00
if ( net__socket_nonblock ( sock ) ) {
2017-02-06 22:39:39 +00:00
continue ;
}
rc = connect ( * sock , rp - > ai_addr , rp - > ai_addrlen ) ;
# ifdef WIN32
errno = WSAGetLastError ( ) ;
# endif
if ( rc = = 0 | | errno = = EINPROGRESS | | errno = = COMPAT_EWOULDBLOCK ) {
if ( rc < 0 & & ( errno = = EINPROGRESS | | errno = = COMPAT_EWOULDBLOCK ) ) {
rc = MOSQ_ERR_CONN_PENDING ;
}
/* Set non-blocking */
2018-08-08 14:23:03 +00:00
if ( net__socket_nonblock ( sock ) ) {
2017-02-06 22:39:39 +00:00
continue ;
}
break ;
}
COMPAT_CLOSE ( * sock ) ;
* sock = INVALID_SOCKET ;
}
2017-02-07 16:11:57 +00:00
freeaddrinfo ( mosq - > adns - > ar_result ) ;
mosq - > adns - > ar_result = NULL ;
2018-12-04 12:39:00 +00:00
mosquitto__free ( ( struct addrinfo * ) mosq - > adns - > ar_request ) ;
2017-03-06 21:19:53 +00:00
mosquitto__free ( mosq - > adns ) ;
2017-02-07 16:11:57 +00:00
mosq - > adns = NULL ;
2017-02-06 22:39:39 +00:00
if ( ! rp ) {
return MOSQ_ERR_ERRNO ;
}
2017-02-07 16:11:57 +00:00
2017-02-06 22:39:39 +00:00
return rc ;
}
# endif
2015-04-29 20:23:59 +00:00
2015-09-03 16:46:55 +00:00
int net__try_connect ( struct mosquitto * mosq , const char * host , uint16_t port , mosq_sock_t * sock , const char * bind_address , bool blocking )
2014-05-07 22:27:00 +00:00
{
struct addrinfo hints ;
struct addrinfo * ainfo , * rp ;
struct addrinfo * ainfo_bind , * rp_bind ;
int s ;
2014-10-24 20:28:24 +00:00
int rc = MOSQ_ERR_SUCCESS ;
2014-05-07 22:27:00 +00:00
# ifdef WIN32
uint32_t val = 1 ;
# endif
* sock = INVALID_SOCKET ;
memset ( & hints , 0 , sizeof ( struct addrinfo ) ) ;
2018-08-01 23:27:52 +00:00
hints . ai_family = AF_UNSPEC ;
2014-05-07 22:27:00 +00:00
hints . ai_socktype = SOCK_STREAM ;
s = getaddrinfo ( host , NULL , & hints , & ainfo ) ;
if ( s ) {
errno = s ;
return MOSQ_ERR_EAI ;
}
if ( bind_address ) {
s = getaddrinfo ( bind_address , NULL , & hints , & ainfo_bind ) ;
if ( s ) {
freeaddrinfo ( ainfo ) ;
errno = s ;
return MOSQ_ERR_EAI ;
}
}
for ( rp = ainfo ; rp ! = NULL ; rp = rp - > ai_next ) {
* sock = socket ( rp - > ai_family , rp - > ai_socktype , rp - > ai_protocol ) ;
if ( * sock = = INVALID_SOCKET ) continue ;
2017-02-06 22:39:39 +00:00
2018-08-01 23:27:52 +00:00
if ( rp - > ai_family = = AF_INET ) {
2014-05-07 22:27:00 +00:00
( ( struct sockaddr_in * ) rp - > ai_addr ) - > sin_port = htons ( port ) ;
2018-08-01 23:27:52 +00:00
} else if ( rp - > ai_family = = AF_INET6 ) {
2014-05-07 22:27:00 +00:00
( ( struct sockaddr_in6 * ) rp - > ai_addr ) - > sin6_port = htons ( port ) ;
} else {
2014-05-27 21:03:01 +00:00
COMPAT_CLOSE ( * sock ) ;
2018-08-08 14:23:03 +00:00
* sock = INVALID_SOCKET ;
2014-05-07 22:27:00 +00:00
continue ;
}
if ( bind_address ) {
for ( rp_bind = ainfo_bind ; rp_bind ! = NULL ; rp_bind = rp_bind - > ai_next ) {
if ( bind ( * sock , rp_bind - > ai_addr , rp_bind - > ai_addrlen ) = = 0 ) {
break ;
}
}
if ( ! rp_bind ) {
COMPAT_CLOSE ( * sock ) ;
2018-08-08 14:23:03 +00:00
* sock = INVALID_SOCKET ;
2014-05-07 22:27:00 +00:00
continue ;
}
}
if ( ! blocking ) {
/* Set non-blocking */
2018-08-08 14:23:03 +00:00
if ( net__socket_nonblock ( sock ) ) {
2014-05-07 22:27:00 +00:00
continue ;
}
}
rc = connect ( * sock , rp - > ai_addr , rp - > ai_addrlen ) ;
# ifdef WIN32
errno = WSAGetLastError ( ) ;
# endif
if ( rc = = 0 | | errno = = EINPROGRESS | | errno = = COMPAT_EWOULDBLOCK ) {
2014-10-24 20:28:24 +00:00
if ( rc < 0 & & ( errno = = EINPROGRESS | | errno = = COMPAT_EWOULDBLOCK ) ) {
rc = MOSQ_ERR_CONN_PENDING ;
}
2014-05-07 22:27:00 +00:00
if ( blocking ) {
/* Set non-blocking */
2018-08-08 14:23:03 +00:00
if ( net__socket_nonblock ( sock ) ) {
2014-05-07 22:27:00 +00:00
continue ;
}
}
break ;
}
COMPAT_CLOSE ( * sock ) ;
* sock = INVALID_SOCKET ;
}
freeaddrinfo ( ainfo ) ;
if ( bind_address ) {
freeaddrinfo ( ainfo_bind ) ;
}
if ( ! rp ) {
return MOSQ_ERR_ERRNO ;
}
2014-10-24 20:28:24 +00:00
return rc ;
2014-05-07 22:27:00 +00:00
}
2015-04-29 20:23:59 +00:00
2015-01-27 23:33:36 +00:00
# ifdef WITH_TLS
2016-05-16 20:57:31 +00:00
void net__print_ssl_error ( struct mosquitto * mosq )
{
char ebuf [ 256 ] ;
unsigned long e ;
e = ERR_get_error ( ) ;
while ( e ) {
log__printf ( mosq , MOSQ_LOG_ERR , " OpenSSL Error: %s " , ERR_error_string ( e , ebuf ) ) ;
e = ERR_get_error ( ) ;
}
}
2015-05-18 08:29:22 +00:00
int net__socket_connect_tls ( struct mosquitto * mosq )
2015-01-27 23:33:36 +00:00
{
2016-05-14 20:45:02 +00:00
int ret , err ;
2017-02-01 22:00:14 +00:00
2017-05-31 09:02:32 +00:00
ERR_clear_error ( ) ;
2015-01-27 23:33:36 +00:00
ret = SSL_connect ( mosq - > ssl ) ;
2016-05-14 20:45:02 +00:00
if ( ret ! = 1 ) {
err = SSL_get_error ( mosq - > ssl , ret ) ;
if ( err = = SSL_ERROR_SYSCALL ) {
mosq - > want_connect = true ;
return MOSQ_ERR_SUCCESS ;
}
if ( err = = SSL_ERROR_WANT_READ ) {
2015-01-27 23:33:36 +00:00
mosq - > want_connect = true ;
/* We always try to read anyway */
2016-05-14 20:45:02 +00:00
} else if ( err = = SSL_ERROR_WANT_WRITE ) {
2015-01-27 23:33:36 +00:00
mosq - > want_write = true ;
mosq - > want_connect = true ;
} else {
2017-03-06 10:58:56 +00:00
net__print_ssl_error ( mosq ) ;
2015-01-27 23:33:36 +00:00
COMPAT_CLOSE ( mosq - > sock ) ;
mosq - > sock = INVALID_SOCKET ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2015-01-27 23:33:36 +00:00
return MOSQ_ERR_TLS ;
}
} else {
mosq - > want_connect = false ;
}
return MOSQ_ERR_SUCCESS ;
}
# endif
2018-04-11 15:34:24 +00:00
2018-05-02 18:10:32 +00:00
# ifdef WITH_TLS
2018-04-11 15:34:24 +00:00
static int net__init_ssl_ctx ( struct mosquitto * mosq )
2014-05-07 22:27:00 +00:00
{
int ret ;
2018-04-11 15:34:24 +00:00
if ( mosq - > ssl_ctx ) {
if ( ! mosq - > ssl_ctx_defaults ) {
return MOSQ_ERR_SUCCESS ;
} else if ( ! mosq - > tls_cafile & & ! mosq - > tls_capath & & ! mosq - > tls_psk ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Error: MOSQ_OPT_SSL_CTX_WITH_DEFAULTS used without specifying cafile, capath or psk. " ) ;
return MOSQ_ERR_INVAL ;
}
}
2018-04-12 20:37:44 +00:00
/* Apply default SSL_CTX settings. This is only used if MOSQ_OPT_SSL_CTX
* has not been set , or if both of MOSQ_OPT_SSL_CTX and
* MOSQ_OPT_SSL_CTX_WITH_DEFAULTS are set . */
2014-05-07 22:27:00 +00:00
if ( mosq - > tls_cafile | | mosq - > tls_capath | | mosq - > tls_psk ) {
2018-04-12 00:11:46 +00:00
if ( ! mosq - > ssl_ctx ) {
2018-04-11 21:10:48 +00:00
# if OPENSSL_VERSION_NUMBER < 0x10100000L
2018-04-12 00:11:46 +00:00
mosq - > ssl_ctx = SSL_CTX_new ( SSLv23_client_method ( ) ) ;
2018-04-11 21:10:48 +00:00
# else
2018-04-12 00:11:46 +00:00
mosq - > ssl_ctx = SSL_CTX_new ( TLS_client_method ( ) ) ;
2018-04-11 21:10:48 +00:00
# endif
2018-04-12 00:11:46 +00:00
if ( ! mosq - > ssl_ctx ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to create TLS context. " ) ;
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2018-04-12 00:11:46 +00:00
net__print_ssl_error ( mosq ) ;
return MOSQ_ERR_TLS ;
}
2018-04-11 21:10:48 +00:00
}
2016-02-09 23:02:46 +00:00
if ( ! mosq - > tls_version ) {
2018-04-11 21:10:48 +00:00
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_SSLv3 ) ;
2016-02-09 23:02:46 +00:00
} else if ( ! strcmp ( mosq - > tls_version , " tlsv1.2 " ) ) {
2018-04-11 21:10:48 +00:00
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1 ) ;
2014-05-07 22:27:00 +00:00
} else if ( ! strcmp ( mosq - > tls_version , " tlsv1.1 " ) ) {
2018-04-11 21:10:48 +00:00
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1 ) ;
2014-05-07 22:27:00 +00:00
} else if ( ! strcmp ( mosq - > tls_version , " tlsv1 " ) ) {
2018-04-11 21:10:48 +00:00
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_1 ) ;
2014-05-07 22:27:00 +00:00
} else {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Protocol %s not supported. " , mosq - > tls_version ) ;
2017-02-06 22:39:39 +00:00
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_INVAL ;
}
2018-04-11 16:10:27 +00:00
2014-05-07 22:27:00 +00:00
/* Disable compression */
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_COMPRESSION ) ;
2018-04-11 16:10:27 +00:00
2014-05-07 22:27:00 +00:00
# ifdef SSL_MODE_RELEASE_BUFFERS
/* Use even less memory per SSL connection. */
SSL_CTX_set_mode ( mosq - > ssl_ctx , SSL_MODE_RELEASE_BUFFERS ) ;
# endif
if ( mosq - > tls_ciphers ) {
ret = SSL_CTX_set_cipher_list ( mosq - > ssl_ctx , mosq - > tls_ciphers ) ;
if ( ret = = 0 ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to set TLS ciphers. Check cipher list \" %s \" . " , mosq - > tls_ciphers ) ;
2017-02-06 22:39:39 +00:00
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
}
if ( mosq - > tls_cafile | | mosq - > tls_capath ) {
ret = SSL_CTX_load_verify_locations ( mosq - > ssl_ctx , mosq - > tls_cafile , mosq - > tls_capath ) ;
if ( ret = = 0 ) {
# ifdef WITH_BROKER
if ( mosq - > tls_cafile & & mosq - > tls_capath ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_cafile \" %s \" and bridge_capath \" %s \" . " , mosq - > tls_cafile , mosq - > tls_capath ) ;
2014-05-07 22:27:00 +00:00
} else if ( mosq - > tls_cafile ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_cafile \" %s \" . " , mosq - > tls_cafile ) ;
2014-05-07 22:27:00 +00:00
} else {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_capath \" %s \" . " , mosq - > tls_capath ) ;
2014-05-07 22:27:00 +00:00
}
# else
if ( mosq - > tls_cafile & & mosq - > tls_capath ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check cafile \" %s \" and capath \" %s \" . " , mosq - > tls_cafile , mosq - > tls_capath ) ;
2014-05-07 22:27:00 +00:00
} else if ( mosq - > tls_cafile ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check cafile \" %s \" . " , mosq - > tls_cafile ) ;
2014-05-07 22:27:00 +00:00
} else {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check capath \" %s \" . " , mosq - > tls_capath ) ;
2014-05-07 22:27:00 +00:00
}
# endif
2017-02-06 22:39:39 +00:00
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
if ( mosq - > tls_cert_reqs = = 0 ) {
SSL_CTX_set_verify ( mosq - > ssl_ctx , SSL_VERIFY_NONE , NULL ) ;
} else {
2015-04-19 21:10:59 +00:00
SSL_CTX_set_verify ( mosq - > ssl_ctx , SSL_VERIFY_PEER , mosquitto__server_certificate_verify ) ;
2014-05-07 22:27:00 +00:00
}
if ( mosq - > tls_pw_callback ) {
SSL_CTX_set_default_passwd_cb ( mosq - > ssl_ctx , mosq - > tls_pw_callback ) ;
SSL_CTX_set_default_passwd_cb_userdata ( mosq - > ssl_ctx , mosq ) ;
}
if ( mosq - > tls_certfile ) {
ret = SSL_CTX_use_certificate_chain_file ( mosq - > ssl_ctx , mosq - > tls_certfile ) ;
if ( ret ! = 1 ) {
# ifdef WITH_BROKER
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load client certificate, check bridge_certfile \" %s \" . " , mosq - > tls_certfile ) ;
2014-05-07 22:27:00 +00:00
# else
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load client certificate \" %s \" . " , mosq - > tls_certfile ) ;
2014-05-07 22:27:00 +00:00
# endif
2017-02-06 22:39:39 +00:00
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
}
if ( mosq - > tls_keyfile ) {
ret = SSL_CTX_use_PrivateKey_file ( mosq - > ssl_ctx , mosq - > tls_keyfile , SSL_FILETYPE_PEM ) ;
if ( ret ! = 1 ) {
# ifdef WITH_BROKER
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load client key file, check bridge_keyfile \" %s \" . " , mosq - > tls_keyfile ) ;
2014-05-07 22:27:00 +00:00
# else
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load client key file \" %s \" . " , mosq - > tls_keyfile ) ;
2014-05-07 22:27:00 +00:00
# endif
2017-02-06 22:39:39 +00:00
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
ret = SSL_CTX_check_private_key ( mosq - > ssl_ctx ) ;
if ( ret ! = 1 ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Client certificate/key are inconsistent. " ) ;
2017-02-06 22:39:39 +00:00
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
}
2018-04-11 16:10:27 +00:00
# ifdef WITH_TLS_PSK
2014-05-07 22:27:00 +00:00
} else if ( mosq - > tls_psk ) {
SSL_CTX_set_psk_client_callback ( mosq - > ssl_ctx , psk_client_callback ) ;
# endif
}
2018-04-11 15:34:24 +00:00
}
return MOSQ_ERR_SUCCESS ;
}
2018-05-02 18:10:32 +00:00
# endif
2018-04-11 15:34:24 +00:00
int net__socket_connect_step3 ( struct mosquitto * mosq , const char * host , uint16_t port , const char * bind_address , bool blocking )
{
# ifdef WITH_TLS
BIO * bio ;
int rc = net__init_ssl_ctx ( mosq ) ;
if ( rc ) return rc ;
2014-05-07 22:27:00 +00:00
2018-04-11 15:34:24 +00:00
if ( mosq - > ssl_ctx ) {
2018-10-23 09:46:55 +00:00
if ( mosq - > ssl ) {
SSL_free ( mosq - > ssl ) ;
}
2014-05-07 22:27:00 +00:00
mosq - > ssl = SSL_new ( mosq - > ssl_ctx ) ;
if ( ! mosq - > ssl ) {
2017-02-06 22:39:39 +00:00
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
2016-11-30 11:31:30 +00:00
2014-05-07 22:27:00 +00:00
SSL_set_ex_data ( mosq - > ssl , tls_ex_index_mosq , mosq ) ;
2017-02-06 22:39:39 +00:00
bio = BIO_new_socket ( mosq - > sock , BIO_NOCLOSE ) ;
2014-05-07 22:27:00 +00:00
if ( ! bio ) {
2017-02-06 22:39:39 +00:00
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
SSL_set_bio ( mosq - > ssl , bio , bio ) ;
2017-11-21 14:58:25 +00:00
/*
* required for the SNI resolving
*/
if ( SSL_set_tlsext_host_name ( mosq - > ssl , host ) ! = 1 ) {
COMPAT_CLOSE ( mosq - > sock ) ;
2018-08-08 14:23:03 +00:00
mosq - > sock = INVALID_SOCKET ;
2017-11-21 14:58:25 +00:00
return MOSQ_ERR_TLS ;
}
2015-05-18 08:29:22 +00:00
if ( net__socket_connect_tls ( mosq ) ) {
2015-01-27 23:33:36 +00:00
return MOSQ_ERR_TLS ;
2014-05-07 22:27:00 +00:00
}
2015-01-27 23:33:36 +00:00
2014-05-07 22:27:00 +00:00
}
# endif
2017-02-06 22:39:39 +00:00
return MOSQ_ERR_SUCCESS ;
}
2018-08-09 14:01:39 +00:00
/* Create a socket and connect it to 'ip' on port 'port'. */
2017-03-06 21:19:53 +00:00
int net__socket_connect ( struct mosquitto * mosq , const char * host , uint16_t port , const char * bind_address , bool blocking )
2017-02-06 22:39:39 +00:00
{
mosq_sock_t sock = INVALID_SOCKET ;
int rc ;
if ( ! mosq | | ! host | | ! port ) return MOSQ_ERR_INVAL ;
2017-03-06 21:19:53 +00:00
rc = net__try_connect ( mosq , host , port , & sock , bind_address , blocking ) ;
2017-02-06 22:39:39 +00:00
if ( rc > 0 ) return rc ;
2014-05-07 22:27:00 +00:00
2018-08-08 14:23:03 +00:00
mosq - > sock = sock ;
2017-03-06 21:19:53 +00:00
rc = net__socket_connect_step3 ( mosq , host , port , bind_address , blocking ) ;
2018-08-02 14:06:09 +00:00
if ( rc ) return rc ;
2014-05-07 22:27:00 +00:00
2018-08-02 14:06:09 +00:00
return MOSQ_ERR_SUCCESS ;
2014-05-07 22:27:00 +00:00
}
2015-05-18 08:29:22 +00:00
ssize_t net__read ( struct mosquitto * mosq , void * buf , size_t count )
2014-05-07 22:27:00 +00:00
{
# ifdef WITH_TLS
int ret ;
int err ;
# endif
assert ( mosq ) ;
errno = 0 ;
# ifdef WITH_TLS
if ( mosq - > ssl ) {
2017-05-31 09:02:32 +00:00
ERR_clear_error ( ) ;
2014-05-07 22:27:00 +00:00
ret = SSL_read ( mosq - > ssl , buf , count ) ;
if ( ret < = 0 ) {
err = SSL_get_error ( mosq - > ssl , ret ) ;
if ( err = = SSL_ERROR_WANT_READ ) {
ret = - 1 ;
errno = EAGAIN ;
} else if ( err = = SSL_ERROR_WANT_WRITE ) {
ret = - 1 ;
mosq - > want_write = true ;
errno = EAGAIN ;
} else {
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
errno = EPROTO ;
}
2018-03-29 06:44:57 +00:00
# ifdef WIN32
WSASetLastError ( errno ) ;
# endif
2014-05-07 22:27:00 +00:00
}
return ( ssize_t ) ret ;
} else {
/* Call normal read/recv */
# endif
# ifndef WIN32
return read ( mosq - > sock , buf , count ) ;
# else
return recv ( mosq - > sock , buf , count , 0 ) ;
# endif
# ifdef WITH_TLS
}
# endif
}
2015-05-18 08:29:22 +00:00
ssize_t net__write ( struct mosquitto * mosq , void * buf , size_t count )
2014-05-07 22:27:00 +00:00
{
# ifdef WITH_TLS
int ret ;
int err ;
# endif
assert ( mosq ) ;
errno = 0 ;
# ifdef WITH_TLS
if ( mosq - > ssl ) {
2016-01-13 21:32:01 +00:00
mosq - > want_write = false ;
2017-05-31 09:02:32 +00:00
ERR_clear_error ( ) ;
2014-05-07 22:27:00 +00:00
ret = SSL_write ( mosq - > ssl , buf , count ) ;
if ( ret < 0 ) {
err = SSL_get_error ( mosq - > ssl , ret ) ;
if ( err = = SSL_ERROR_WANT_READ ) {
ret = - 1 ;
errno = EAGAIN ;
} else if ( err = = SSL_ERROR_WANT_WRITE ) {
ret = - 1 ;
mosq - > want_write = true ;
errno = EAGAIN ;
} else {
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
errno = EPROTO ;
}
2018-03-29 06:44:57 +00:00
# ifdef WIN32
WSASetLastError ( errno ) ;
# endif
2014-05-07 22:27:00 +00:00
}
return ( ssize_t ) ret ;
} else {
/* Call normal write/send */
# endif
# ifndef WIN32
return write ( mosq - > sock , buf , count ) ;
# else
return send ( mosq - > sock , buf , count , 0 ) ;
# endif
# ifdef WITH_TLS
}
# endif
}
2018-08-08 14:23:03 +00:00
int net__socket_nonblock ( mosq_sock_t * sock )
2014-05-07 22:27:00 +00:00
{
# ifndef WIN32
int opt ;
/* Set non-blocking */
2018-08-08 14:23:03 +00:00
opt = fcntl ( * sock , F_GETFL , 0 ) ;
2014-05-07 22:27:00 +00:00
if ( opt = = - 1 ) {
2018-08-08 14:23:03 +00:00
COMPAT_CLOSE ( * sock ) ;
* sock = INVALID_SOCKET ;
2018-08-02 13:33:29 +00:00
return MOSQ_ERR_ERRNO ;
2014-05-07 22:27:00 +00:00
}
2018-08-08 14:23:03 +00:00
if ( fcntl ( * sock , F_SETFL , opt | O_NONBLOCK ) = = - 1 ) {
2014-05-07 22:27:00 +00:00
/* If either fcntl fails, don't want to allow this client to connect. */
2018-08-08 14:23:03 +00:00
COMPAT_CLOSE ( * sock ) ;
2018-08-02 13:33:29 +00:00
return MOSQ_ERR_ERRNO ;
2014-05-07 22:27:00 +00:00
}
# else
2014-07-22 09:28:55 +00:00
unsigned long opt = 1 ;
2018-08-08 14:23:03 +00:00
if ( ioctlsocket ( * sock , FIONBIO , & opt ) ) {
COMPAT_CLOSE ( * sock ) ;
2018-08-02 13:33:29 +00:00
return MOSQ_ERR_ERRNO ;
2014-05-07 22:27:00 +00:00
}
# endif
2018-08-02 13:33:29 +00:00
return MOSQ_ERR_SUCCESS ;
2014-05-07 22:27:00 +00:00
}
# ifndef WITH_BROKER
2015-09-03 16:46:55 +00:00
int net__socketpair ( mosq_sock_t * pairR , mosq_sock_t * pairW )
2014-05-07 22:27:00 +00:00
{
# ifdef WIN32
int family [ 2 ] = { AF_INET , AF_INET6 } ;
int i ;
struct sockaddr_storage ss ;
struct sockaddr_in * sa = ( struct sockaddr_in * ) & ss ;
struct sockaddr_in6 * sa6 = ( struct sockaddr_in6 * ) & ss ;
socklen_t ss_len ;
2015-03-29 09:43:08 +00:00
mosq_sock_t spR , spW ;
2014-05-07 22:27:00 +00:00
2015-03-29 09:43:08 +00:00
mosq_sock_t listensock ;
2014-05-07 22:27:00 +00:00
2015-03-29 09:43:08 +00:00
* pairR = INVALID_SOCKET ;
* pairW = INVALID_SOCKET ;
2014-05-07 22:27:00 +00:00
for ( i = 0 ; i < 2 ; i + + ) {
memset ( & ss , 0 , sizeof ( ss ) ) ;
if ( family [ i ] = = AF_INET ) {
sa - > sin_family = family [ i ] ;
sa - > sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ;
sa - > sin_port = 0 ;
ss_len = sizeof ( struct sockaddr_in ) ;
} else if ( family [ i ] = = AF_INET6 ) {
sa6 - > sin6_family = family [ i ] ;
sa6 - > sin6_addr = in6addr_loopback ;
sa6 - > sin6_port = 0 ;
ss_len = sizeof ( struct sockaddr_in6 ) ;
} else {
return MOSQ_ERR_INVAL ;
}
listensock = socket ( family [ i ] , SOCK_STREAM , IPPROTO_TCP ) ;
if ( listensock = = - 1 ) {
continue ;
}
if ( bind ( listensock , ( struct sockaddr * ) & ss , ss_len ) = = - 1 ) {
COMPAT_CLOSE ( listensock ) ;
continue ;
}
if ( listen ( listensock , 1 ) = = - 1 ) {
COMPAT_CLOSE ( listensock ) ;
continue ;
}
memset ( & ss , 0 , sizeof ( ss ) ) ;
ss_len = sizeof ( ss ) ;
if ( getsockname ( listensock , ( struct sockaddr * ) & ss , & ss_len ) < 0 ) {
COMPAT_CLOSE ( listensock ) ;
continue ;
}
if ( family [ i ] = = AF_INET ) {
sa - > sin_family = family [ i ] ;
sa - > sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ;
ss_len = sizeof ( struct sockaddr_in ) ;
} else if ( family [ i ] = = AF_INET6 ) {
sa6 - > sin6_family = family [ i ] ;
sa6 - > sin6_addr = in6addr_loopback ;
ss_len = sizeof ( struct sockaddr_in6 ) ;
}
spR = socket ( family [ i ] , SOCK_STREAM , IPPROTO_TCP ) ;
if ( spR = = - 1 ) {
COMPAT_CLOSE ( listensock ) ;
continue ;
}
2018-08-08 14:23:03 +00:00
if ( net__socket_nonblock ( & spR ) ) {
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( listensock ) ;
continue ;
}
if ( connect ( spR , ( struct sockaddr * ) & ss , ss_len ) < 0 ) {
# ifdef WIN32
errno = WSAGetLastError ( ) ;
# endif
if ( errno ! = EINPROGRESS & & errno ! = COMPAT_EWOULDBLOCK ) {
COMPAT_CLOSE ( spR ) ;
COMPAT_CLOSE ( listensock ) ;
continue ;
}
}
spW = accept ( listensock , NULL , 0 ) ;
if ( spW = = - 1 ) {
# ifdef WIN32
errno = WSAGetLastError ( ) ;
# endif
if ( errno ! = EINPROGRESS & & errno ! = COMPAT_EWOULDBLOCK ) {
COMPAT_CLOSE ( spR ) ;
COMPAT_CLOSE ( listensock ) ;
continue ;
}
}
2018-08-08 14:23:03 +00:00
if ( net__socket_nonblock ( & spW ) ) {
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( spR ) ;
COMPAT_CLOSE ( listensock ) ;
continue ;
}
COMPAT_CLOSE ( listensock ) ;
* pairR = spR ;
* pairW = spW ;
return MOSQ_ERR_SUCCESS ;
}
return MOSQ_ERR_UNKNOWN ;
# else
int sv [ 2 ] ;
if ( socketpair ( AF_UNIX , SOCK_STREAM , 0 , sv ) = = - 1 ) {
return MOSQ_ERR_ERRNO ;
}
2018-08-08 14:23:03 +00:00
if ( net__socket_nonblock ( & sv [ 0 ] ) ) {
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( sv [ 1 ] ) ;
return MOSQ_ERR_ERRNO ;
}
2018-08-08 14:23:03 +00:00
if ( net__socket_nonblock ( & sv [ 1 ] ) ) {
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( sv [ 0 ] ) ;
return MOSQ_ERR_ERRNO ;
}
* pairR = sv [ 0 ] ;
* pairW = sv [ 1 ] ;
return MOSQ_ERR_SUCCESS ;
# endif
}
# endif