2014-05-07 22:27:00 +00:00
/*
2020-02-27 23:26:58 +00:00
Copyright ( c ) 2009 - 2020 Roger Light < roger @ atchoo . org >
2014-05-07 22:27:00 +00:00
All rights reserved . This program and the accompanying materials
2020-11-25 17:34:21 +00:00
are made available under the terms of the Eclipse Public License 2.0
2014-05-07 22:27:00 +00:00
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
2020-11-25 17:34:21 +00:00
https : //www.eclipse.org/legal/epl-2.0/
2014-05-07 22:27:00 +00:00
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
2021-01-20 11:46:18 +00:00
SPDX - License - Identifier : EPL - 2.0 OR BSD - 3 - Clause
2020-12-01 18:21:59 +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>
2019-12-18 13:47:34 +00:00
# include <netinet/tcp.h>
2014-05-07 22:27:00 +00:00
# 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
2019-10-08 19:49:34 +00:00
# ifdef WITH_UNIX_SOCKETS
# include <sys / un.h>
# endif
2014-05-07 22:27:00 +00:00
# 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>
2019-05-02 16:22:42 +00:00
# include <openssl/ui.h>
2014-05-07 22:27:00 +00:00
# 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"
2018-08-29 21:26:16 +00:00
# include "mqtt_protocol.h"
2015-04-29 20:37:47 +00:00
# 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 ;
2018-08-09 19:37:33 +00:00
UI_METHOD * _ui_method = NULL ;
2020-05-18 19:25:37 +00:00
static bool is_tls_initialized = false ;
2018-08-09 19:37:33 +00:00
/* Functions taken from OpenSSL s_server/s_client */
static int ui_open ( UI * ui )
{
return UI_method_get_opener ( UI_OpenSSL ( ) ) ( ui ) ;
}
static int ui_read ( UI * ui , UI_STRING * uis )
{
return UI_method_get_reader ( UI_OpenSSL ( ) ) ( ui , uis ) ;
}
static int ui_write ( UI * ui , UI_STRING * uis )
{
return UI_method_get_writer ( UI_OpenSSL ( ) ) ( ui , uis ) ;
}
static int ui_close ( UI * ui )
{
return UI_method_get_closer ( UI_OpenSSL ( ) ) ( ui ) ;
}
static void setup_ui_method ( void )
{
_ui_method = UI_create_method ( " OpenSSL application user interface " ) ;
UI_method_set_opener ( _ui_method , ui_open ) ;
UI_method_set_reader ( _ui_method , ui_read ) ;
UI_method_set_writer ( _ui_method , ui_write ) ;
UI_method_set_closer ( _ui_method , ui_close ) ;
}
2019-03-14 09:53:23 +00:00
static void cleanup_ui_method ( void )
{
if ( _ui_method ) {
UI_destroy_method ( _ui_method ) ;
2019-04-29 22:29:05 +00:00
_ui_method = NULL ;
2019-03-14 09:53:23 +00:00
}
}
2018-08-09 19:37:33 +00:00
UI_METHOD * net__get_ui_method ( void )
{
return _ui_method ;
}
2020-05-18 19:25:37 +00:00
2014-05-07 22:27:00 +00:00
# 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
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
2019-02-28 12:21:11 +00:00
# if OPENSSL_VERSION_NUMBER < 0x10100000L
2019-01-10 17:44:46 +00:00
CRYPTO_cleanup_all_ex_data ( ) ;
2014-05-07 22:27:00 +00:00
ERR_free_strings ( ) ;
2019-02-28 12:21:11 +00:00
ERR_remove_thread_state ( NULL ) ;
2014-05-07 22:27:00 +00:00
EVP_cleanup ( ) ;
2019-01-10 17:44:46 +00:00
# if !defined(OPENSSL_NO_ENGINE)
ENGINE_cleanup ( ) ;
# endif
2020-05-18 19:25:37 +00:00
is_tls_initialized = false ;
2019-01-10 17:44:46 +00:00
# endif
CONF_modules_unload ( 1 ) ;
2019-03-14 09:53:23 +00:00
cleanup_ui_method ( ) ;
2014-05-07 22:27:00 +00:00
# endif
# ifdef WITH_SRV
ares_library_cleanup ( ) ;
# endif
# ifdef WIN32
WSACleanup ( ) ;
# endif
}
2020-05-18 19:25:37 +00:00
# ifdef WITH_TLS
void net__init_tls ( void )
{
if ( is_tls_initialized ) return ;
# if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_load_error_strings ( ) ;
SSL_library_init ( ) ;
OpenSSL_add_all_algorithms ( ) ;
# else
OPENSSL_init_crypto ( OPENSSL_INIT_ADD_ALL_CIPHERS \
| OPENSSL_INIT_ADD_ALL_DIGESTS \
| OPENSSL_INIT_LOAD_CONFIG , NULL ) ;
# endif
# if !defined(OPENSSL_NO_ENGINE)
ENGINE_load_builtin_engines ( ) ;
# endif
setup_ui_method ( ) ;
if ( tls_ex_index_mosq = = - 1 ) {
tls_ex_index_mosq = SSL_get_ex_new_index ( 0 , " client context " , NULL , NULL , NULL ) ;
}
is_tls_initialized = true ;
}
# endif
2014-05-07 22:27:00 +00:00
/* Close a socket associated with a context and set it to -1.
* Returns 1 on failure ( context is NULL )
* Returns 0 on success .
*/
2015-05-18 08:29:22 +00:00
int net__socket_close ( struct mosquitto * mosq )
2014-05-07 22:27:00 +00:00
{
int rc = 0 ;
2020-11-18 15:36:34 +00:00
# ifdef WITH_BROKER
struct mosquitto * mosq_found ;
# endif
2014-05-07 22:27:00 +00:00
assert ( mosq ) ;
# ifdef WITH_TLS
2017-07-26 23:12:32 +00:00
# ifdef WITH_WEBSOCKETS
if ( ! mosq - > wsi )
# endif
{
if ( mosq - > ssl ) {
2020-02-04 17:11:11 +00:00
if ( ! SSL_in_init ( mosq - > ssl ) ) {
SSL_shutdown ( mosq - > ssl ) ;
}
2017-07-26 23:12:32 +00:00
SSL_free ( mosq - > ssl ) ;
mosq - > ssl = 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 ) {
2019-09-25 11:17:17 +00:00
mosquitto__set_state ( mosq , mosq_cs_disconnect_ws ) ;
2014-06-29 22:16:10 +00:00
}
2020-12-01 13:39:33 +00:00
lws_callback_on_writable ( mosq - > wsi ) ;
2017-07-27 13:56:10 +00:00
} else
2014-06-29 22:16:10 +00:00
# endif
2017-07-27 13:56:10 +00:00
{
2019-02-12 17:05:42 +00:00
if ( mosq - > sock ! = INVALID_SOCKET ) {
2017-07-27 13:56:10 +00:00
# ifdef WITH_BROKER
2020-11-18 15:36:34 +00:00
HASH_FIND ( hh_sock , db . contexts_by_sock , & mosq - > sock , sizeof ( mosq - > sock ) , mosq_found ) ;
if ( mosq_found ) {
HASH_DELETE ( hh_sock , db . contexts_by_sock , mosq_found ) ;
}
2017-07-27 13:56:10 +00:00
# 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 - - ;
2021-08-17 12:10:18 +00:00
mosq - > listener = NULL ;
2014-06-03 15:21:46 +00:00
}
# endif
2014-05-07 22:27:00 +00:00
return rc ;
}
2015-04-29 20:23:59 +00:00
2018-12-09 13:40:38 +00:00
# ifdef FINAL_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 ;
2019-03-13 14:11:50 +00:00
UNUSED ( hint ) ;
2014-05-07 22:27:00 +00:00
mosq = SSL_get_ex_data ( ssl , tls_ex_index_mosq ) ;
if ( ! mosq ) return 0 ;
snprintf ( identity , max_identity_len , " %s " , mosq - > tls_psk_identity ) ;
2020-10-17 00:23:08 +00:00
len = mosquitto__hex2bin ( mosq - > tls_psk , psk , ( int ) max_psk_len ) ;
2014-05-07 22:27:00 +00:00
if ( len < 0 ) return 0 ;
2020-10-17 00:23:08 +00:00
return ( unsigned int ) len ;
2014-05-07 22:27:00 +00:00
}
# 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
2019-10-08 19:49:34 +00:00
static int net__try_connect_tcp ( 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
2020-12-02 15:59:45 +00:00
ainfo_bind = NULL ;
2014-05-07 22:27:00 +00:00
* 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
2019-10-08 19:49:34 +00:00
# ifdef WITH_UNIX_SOCKETS
static int net__try_connect_unix ( const char * host , mosq_sock_t * sock )
{
struct sockaddr_un addr ;
int s ;
int rc ;
if ( host = = NULL | | strlen ( host ) = = 0 | | strlen ( host ) > sizeof ( addr . sun_path ) - 1 ) {
return MOSQ_ERR_INVAL ;
}
memset ( & addr , 0 , sizeof ( struct sockaddr_un ) ) ;
addr . sun_family = AF_UNIX ;
strncpy ( addr . sun_path , host , sizeof ( addr . sun_path ) - 1 ) ;
s = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
if ( s < 0 ) {
return MOSQ_ERR_ERRNO ;
}
rc = net__socket_nonblock ( & s ) ;
if ( rc ) return rc ;
rc = connect ( s , ( struct sockaddr * ) & addr , sizeof ( struct sockaddr_un ) ) ;
if ( rc < 0 ) {
close ( s ) ;
return MOSQ_ERR_ERRNO ;
}
* sock = s ;
return 0 ;
}
# endif
int net__try_connect ( const char * host , uint16_t port , mosq_sock_t * sock , const char * bind_address , bool blocking )
{
if ( port = = 0 ) {
# ifdef WITH_UNIX_SOCKETS
return net__try_connect_unix ( host , sock ) ;
# else
return MOSQ_ERR_NOT_SUPPORTED ;
# endif
} else {
return net__try_connect_tcp ( host , port , sock , bind_address , blocking ) ;
}
}
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 ;
2020-02-04 16:59:29 +00:00
int num = 0 ;
2016-05-16 20:57:31 +00:00
e = ERR_get_error ( ) ;
while ( e ) {
2020-02-04 16:59:29 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " OpenSSL Error[%d]: %s " , num , ERR_error_string ( e , ebuf ) ) ;
2016-05-16 20:57:31 +00:00
e = ERR_get_error ( ) ;
2020-02-04 16:59:29 +00:00
num + + ;
2016-05-16 20:57:31 +00:00
}
}
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 ;
2020-03-12 10:29:11 +00:00
long res ;
2017-02-01 22:00:14 +00:00
2017-05-31 09:02:32 +00:00
ERR_clear_error ( ) ;
2017-06-09 13:52:50 +00:00
if ( mosq - > tls_ocsp_required ) {
2020-03-12 10:29:11 +00:00
/* Note: OCSP is available in all currently supported OpenSSL versions. */
2017-06-09 13:52:50 +00:00
if ( ( res = SSL_set_tlsext_status_type ( mosq - > ssl , TLSEXT_STATUSTYPE_ocsp ) ) ! = 1 ) {
2019-03-26 18:36:13 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Could not activate OCSP (error: %ld) " , res ) ;
2017-06-09 13:52:50 +00:00
return MOSQ_ERR_OCSP ;
}
2019-03-26 18:36:13 +00:00
if ( ( res = SSL_CTX_set_tlsext_status_cb ( mosq - > ssl_ctx , mosquitto__verify_ocsp_status_cb ) ) ! = 1 ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Could not activate OCSP (error: %ld) " , res ) ;
2017-06-09 13:52:50 +00:00
return MOSQ_ERR_OCSP ;
}
if ( ( res = SSL_CTX_set_tlsext_status_arg ( mosq - > ssl_ctx , mosq ) ) ! = 1 ) {
2019-03-26 18:36:13 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Could not activate OCSP (error: %ld) " , res ) ;
2017-06-09 13:52:50 +00:00
return MOSQ_ERR_OCSP ;
}
}
2022-08-05 21:14:37 +00:00
SSL_set_connect_state ( mosq - > ssl ) ;
2015-01-27 23:33:36 +00:00
return MOSQ_ERR_SUCCESS ;
}
# endif
2018-04-11 15:34:24 +00:00
2018-05-02 18:10:32 +00:00
# ifdef WITH_TLS
2020-05-12 12:39:49 +00:00
static int net__tls_load_ca ( struct mosquitto * mosq )
{
int ret ;
2020-12-01 11:51:13 +00:00
if ( mosq - > tls_use_os_certs ) {
SSL_CTX_set_default_verify_paths ( mosq - > ssl_ctx ) ;
}
2020-05-12 12:39:49 +00:00
# if OPENSSL_VERSION_NUMBER < 0x30000000L
2020-12-01 11:51:13 +00:00
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 ) {
2020-05-12 12:39:49 +00:00
# ifdef WITH_BROKER
2020-12-01 11:51:13 +00:00
if ( mosq - > tls_cafile & & mosq - > tls_capath ) {
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 ) ;
} else if ( mosq - > tls_cafile ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_cafile \" %s \" . " , mosq - > tls_cafile ) ;
} else {
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_capath \" %s \" . " , mosq - > tls_capath ) ;
}
2020-05-12 12:39:49 +00:00
# else
2020-12-01 11:51:13 +00:00
if ( mosq - > tls_cafile & & mosq - > tls_capath ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check cafile \" %s \" and capath \" %s \" . " , mosq - > tls_cafile , mosq - > tls_capath ) ;
} else if ( mosq - > tls_cafile ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check cafile \" %s \" . " , mosq - > tls_cafile ) ;
} else {
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check capath \" %s \" . " , mosq - > tls_capath ) ;
}
2020-05-12 12:39:49 +00:00
# endif
2020-12-01 11:51:13 +00:00
return MOSQ_ERR_TLS ;
}
2020-05-12 12:39:49 +00:00
}
# else
if ( mosq - > tls_cafile ) {
ret = SSL_CTX_load_verify_file ( mosq - > ssl_ctx , mosq - > tls_cafile ) ;
if ( ret = = 0 ) {
# ifdef WITH_BROKER
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_cafile \" %s \" . " , mosq - > tls_cafile ) ;
# else
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check cafile \" %s \" . " , mosq - > tls_cafile ) ;
# endif
return MOSQ_ERR_TLS ;
}
}
if ( mosq - > tls_capath ) {
ret = SSL_CTX_load_verify_dir ( mosq - > ssl_ctx , mosq - > tls_capath ) ;
if ( ret = = 0 ) {
# ifdef WITH_BROKER
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_capath \" %s \" . " , mosq - > tls_capath ) ;
# else
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check capath \" %s \" . " , mosq - > tls_capath ) ;
# endif
return MOSQ_ERR_TLS ;
}
}
# endif
return MOSQ_ERR_SUCCESS ;
}
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-08-09 19:37:33 +00:00
ENGINE * engine = NULL ;
2019-04-04 23:38:08 +00:00
uint8_t tls_alpn_wire [ 256 ] ;
uint8_t tls_alpn_len ;
2020-03-12 10:29:11 +00:00
# if !defined(OPENSSL_NO_ENGINE)
EVP_PKEY * pkey ;
# endif
2021-10-05 14:20:37 +00:00
2021-08-31 14:59:40 +00:00
# ifndef WITH_BROKER
if ( mosq - > user_ssl_ctx ) {
mosq - > ssl_ctx = mosq - > user_ssl_ctx ;
2018-04-11 15:34:24 +00:00
if ( ! mosq - > ssl_ctx_defaults ) {
return MOSQ_ERR_SUCCESS ;
} else if ( ! mosq - > tls_cafile & & ! mosq - > tls_capath & & ! mosq - > tls_psk ) {
2021-08-31 14:59:40 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: If you use MOSQ_OPT_SSL_CTX then MOSQ_OPT_SSL_CTX_WITH_DEFAULTS must be true, or at least one of cafile, capath or psk must be specified. " ) ;
2018-04-11 15:34:24 +00:00
return MOSQ_ERR_INVAL ;
}
}
2021-08-31 14:59:40 +00:00
# endif
2018-04-11 15:34:24 +00:00
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 . */
2020-12-01 11:51:13 +00:00
if ( mosq - > tls_cafile | | mosq - > tls_capath | | mosq - > tls_psk | | mosq - > tls_use_os_certs ) {
2022-08-10 16:18:33 +00:00
net__init_tls ( ) ;
2018-04-12 00:11:46 +00:00
if ( ! mosq - > ssl_ctx ) {
2020-05-18 19:25:37 +00:00
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. " ) ;
net__print_ssl_error ( mosq ) ;
return MOSQ_ERR_TLS ;
}
2018-04-11 21:10:48 +00:00
}
2021-08-19 16:18:59 +00:00
# ifdef SSL_OP_NO_TLSv1_3
if ( mosq - > tls_psk ) {
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_TLSv1_3 ) ;
}
# endif
2016-02-09 23:02:46 +00:00
if ( ! mosq - > tls_version ) {
2023-03-28 00:15:28 +00:00
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 ) ;
2019-02-28 11:23:26 +00:00
# ifdef SSL_OP_NO_TLSv1_3
2019-02-27 22:50:01 +00:00
} else if ( ! strcmp ( mosq - > tls_version , " tlsv1.3 " ) ) {
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 ) ;
2020-10-27 16:44:03 +00:00
# endif
2019-02-28 11:23:26 +00:00
} else if ( ! strcmp ( mosq - > tls_version , " tlsv1.2 " ) ) {
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 ) ;
} else if ( ! strcmp ( mosq - > tls_version , " tlsv1.1 " ) ) {
2020-10-27 16:44:03 +00:00
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 ) ;
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 ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_INVAL ;
}
2018-04-11 16:10:27 +00:00
2020-12-09 15:49:57 +00:00
# if OPENSSL_VERSION_NUMBER >= 0x10100000L
/* Allow use of DHE ciphers */
SSL_CTX_set_dh_auto ( mosq - > ssl_ctx , 1 ) ;
# endif
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
2019-04-04 23:38:08 +00:00
/* Set ALPN */
if ( mosq - > tls_alpn ) {
tls_alpn_len = ( uint8_t ) strnlen ( mosq - > tls_alpn , 254 ) ;
2020-03-12 10:29:11 +00:00
tls_alpn_wire [ 0 ] = tls_alpn_len ; /* first byte is length of string */
2019-04-04 23:38:08 +00:00
memcpy ( tls_alpn_wire + 1 , mosq - > tls_alpn , tls_alpn_len ) ;
2020-10-17 00:23:08 +00:00
SSL_CTX_set_alpn_protos ( mosq - > ssl_ctx , tls_alpn_wire , tls_alpn_len + 1U ) ;
2019-04-04 23:38:08 +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
2019-05-02 16:37:03 +00:00
# if !defined(OPENSSL_NO_ENGINE)
2018-08-09 19:37:33 +00:00
if ( mosq - > tls_engine ) {
engine = ENGINE_by_id ( mosq - > tls_engine ) ;
if ( ! engine ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Error loading %s engine \n " , mosq - > tls_engine ) ;
return MOSQ_ERR_TLS ;
}
if ( ! ENGINE_init ( engine ) ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Failed engine initialisation \n " ) ;
ENGINE_free ( engine ) ;
return MOSQ_ERR_TLS ;
}
ENGINE_set_default ( engine , ENGINE_METHOD_ALL ) ;
ENGINE_free ( engine ) ; /* release the structural reference from ENGINE_by_id() */
}
2019-05-02 16:37:03 +00:00
# endif
2018-08-09 19:37:33 +00:00
2014-05-07 22:27:00 +00:00
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 ) ;
2019-05-02 16:37:03 +00:00
# if !defined(OPENSSL_NO_ENGINE)
2018-08-09 19:37:33 +00:00
ENGINE_FINISH ( engine ) ;
2019-05-02 16:37:03 +00:00
# endif
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 ;
}
}
2020-12-01 11:51:13 +00:00
if ( mosq - > tls_cafile | | mosq - > tls_capath | | mosq - > tls_use_os_certs ) {
2020-05-12 12:39:49 +00:00
ret = net__tls_load_ca ( mosq ) ;
if ( ret ! = MOSQ_ERR_SUCCESS ) {
# if !defined(OPENSSL_NO_ENGINE)
2018-08-09 19:37:33 +00:00
ENGINE_FINISH ( engine ) ;
2020-05-12 12:39:49 +00:00
# endif
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
2019-05-02 16:37:03 +00:00
# if !defined(OPENSSL_NO_ENGINE)
2018-08-09 19:37:33 +00:00
ENGINE_FINISH ( engine ) ;
2019-05-02 16:37:03 +00:00
# endif
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 ) {
2018-08-09 19:37:33 +00:00
if ( mosq - > tls_keyform = = mosq_k_engine ) {
2019-05-02 16:37:03 +00:00
# if !defined(OPENSSL_NO_ENGINE)
2018-08-11 16:57:58 +00:00
UI_METHOD * ui_method = net__get_ui_method ( ) ;
2019-02-26 17:11:29 +00:00
if ( mosq - > tls_engine_kpass_sha1 ) {
2018-08-11 16:57:58 +00:00
if ( ! ENGINE_ctrl_cmd ( engine , ENGINE_SECRET_MODE , ENGINE_SECRET_MODE_SHA , NULL , NULL , 0 ) ) {
2019-02-26 17:11:29 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to set engine secret mode sha1 " ) ;
2018-08-11 16:57:58 +00:00
ENGINE_FINISH ( engine ) ;
net__print_ssl_error ( mosq ) ;
return MOSQ_ERR_TLS ;
}
2019-02-26 17:11:29 +00:00
if ( ! ENGINE_ctrl_cmd ( engine , ENGINE_PIN , 0 , mosq - > tls_engine_kpass_sha1 , NULL , 0 ) ) {
2018-08-11 16:57:58 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to set engine pin " ) ;
ENGINE_FINISH ( engine ) ;
net__print_ssl_error ( mosq ) ;
return MOSQ_ERR_TLS ;
}
ui_method = NULL ;
}
2020-03-12 10:29:11 +00:00
pkey = ENGINE_load_private_key ( engine , mosq - > tls_keyfile , ui_method , NULL ) ;
2018-08-09 19:37:33 +00:00
if ( ! pkey ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load engine private key file \" %s \" . " , mosq - > tls_keyfile ) ;
ENGINE_FINISH ( engine ) ;
net__print_ssl_error ( mosq ) ;
return MOSQ_ERR_TLS ;
}
if ( SSL_CTX_use_PrivateKey ( mosq - > ssl_ctx , pkey ) < = 0 ) {
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to use engine private key file \" %s \" . " , mosq - > tls_keyfile ) ;
ENGINE_FINISH ( engine ) ;
net__print_ssl_error ( mosq ) ;
return MOSQ_ERR_TLS ;
}
2019-05-02 16:37:03 +00:00
# endif
2018-08-09 19:37:33 +00:00
} else {
ret = SSL_CTX_use_PrivateKey_file ( mosq - > ssl_ctx , mosq - > tls_keyfile , SSL_FILETYPE_PEM ) ;
if ( ret ! = 1 ) {
2014-05-07 22:27:00 +00:00
# ifdef WITH_BROKER
2018-08-09 19:37:33 +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
2018-08-09 19:37:33 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load client key file \" %s \" . " , mosq - > tls_keyfile ) ;
# endif
2019-05-02 16:37:03 +00:00
# if !defined(OPENSSL_NO_ENGINE)
2018-08-09 19:37:33 +00:00
ENGINE_FINISH ( engine ) ;
2019-05-02 16:37:03 +00:00
# endif
2018-08-09 19:37:33 +00:00
net__print_ssl_error ( mosq ) ;
return MOSQ_ERR_TLS ;
}
2014-05-07 22:27:00 +00:00
}
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. " ) ;
2019-05-02 16:37:03 +00:00
# if !defined(OPENSSL_NO_ENGINE)
2018-08-09 19:37:33 +00:00
ENGINE_FINISH ( engine ) ;
2019-05-02 16:37:03 +00:00
# endif
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-12-09 13:40:38 +00:00
# ifdef FINAL_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 ) ;
2021-08-17 14:40:44 +00:00
if ( mosq - > tls_ciphers = = NULL ) {
SSL_CTX_set_cipher_list ( mosq - > ssl_ctx , " PSK " ) ;
}
2014-05-07 22:27:00 +00:00
# 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
2019-01-15 13:21:12 +00:00
int net__socket_connect_step3 ( struct mosquitto * mosq , const char * host )
2018-04-11 15:34:24 +00:00
{
# ifdef WITH_TLS
BIO * bio ;
int rc = net__init_ssl_ctx ( mosq ) ;
2020-11-18 15:36:34 +00:00
if ( rc ) {
2020-11-18 17:16:50 +00:00
net__socket_close ( mosq ) ;
2020-11-18 15:36:34 +00:00
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 ) {
2020-11-18 17:16:50 +00:00
net__socket_close ( mosq ) ;
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 ) {
2020-11-18 17:16:50 +00:00
net__socket_close ( mosq ) ;
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 ) {
2020-11-18 17:16:50 +00:00
net__socket_close ( mosq ) ;
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 ) ) {
2020-11-18 17:16:50 +00:00
net__socket_close ( 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
}
2021-08-26 09:54:03 +00:00
# else
UNUSED ( mosq ) ;
UNUSED ( host ) ;
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
{
2018-02-14 09:28:11 +00:00
int rc , rc2 ;
2017-02-06 22:39:39 +00:00
2020-08-06 12:43:57 +00:00
if ( ! mosq | | ! host ) return MOSQ_ERR_INVAL ;
2017-02-06 22:39:39 +00:00
2021-04-02 10:02:13 +00:00
rc = net__try_connect ( host , port , & mosq - > 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
2019-12-18 13:47:34 +00:00
if ( mosq - > tcp_nodelay ) {
int flag = 1 ;
2020-12-02 15:59:45 +00:00
if ( setsockopt ( mosq - > sock , IPPROTO_TCP , TCP_NODELAY , ( const void * ) & flag , sizeof ( int ) ) ! = 0 ) {
2019-12-18 13:47:34 +00:00
log__printf ( mosq , MOSQ_LOG_WARNING , " Warning: Unable to set TCP_NODELAY. " ) ;
}
}
2019-02-06 12:22:29 +00:00
# if defined(WITH_SOCKS) && !defined(WITH_BROKER)
2019-01-15 13:21:12 +00:00
if ( ! mosq - > socks5_host )
# endif
{
2018-02-14 09:28:11 +00:00
rc2 = net__socket_connect_step3 ( mosq , host ) ;
if ( rc2 ) return rc2 ;
2019-01-15 13:21:12 +00:00
}
2014-05-07 22:27:00 +00:00
2021-01-26 13:19:08 +00:00
return rc ;
2014-05-07 22:27:00 +00:00
}
2021-06-08 10:59:12 +00:00
# ifdef WITH_TLS
2021-06-08 15:51:23 +00:00
static int net__handle_ssl ( struct mosquitto * mosq , int ret )
2021-06-08 10:59:12 +00:00
{
int err ;
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 ;
# ifdef WITH_BROKER
mux__add_out ( mosq ) ;
# else
mosq - > want_write = true ;
# endif
errno = EAGAIN ;
}
else {
net__print_ssl_error ( mosq ) ;
errno = EPROTO ;
}
ERR_clear_error ( ) ;
# ifdef WIN32
WSASetLastError ( errno ) ;
# endif
return ret ;
}
# endif
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 ;
# endif
assert ( mosq ) ;
errno = 0 ;
# ifdef WITH_TLS
if ( mosq - > ssl ) {
2020-10-17 00:23:08 +00:00
ret = SSL_read ( mosq - > ssl , buf , ( int ) count ) ;
2014-05-07 22:27:00 +00:00
if ( ret < = 0 ) {
2021-06-08 10:59:12 +00:00
ret = net__handle_ssl ( mosq , ret ) ;
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
}
2021-01-03 20:52:45 +00:00
ssize_t net__write ( struct mosquitto * mosq , const void * buf , size_t count )
2014-05-07 22:27:00 +00:00
{
# ifdef WITH_TLS
int ret ;
# endif
assert ( mosq ) ;
errno = 0 ;
# ifdef WITH_TLS
if ( mosq - > ssl ) {
2016-01-13 21:32:01 +00:00
mosq - > want_write = false ;
2020-10-17 00:23:08 +00:00
ret = SSL_write ( mosq - > ssl , buf , ( int ) count ) ;
2014-05-07 22:27:00 +00:00
if ( ret < 0 ) {
2021-06-08 10:59:12 +00:00
ret = net__handle_ssl ( mosq , ret ) ;
2014-05-07 22:27:00 +00:00
}
return ( ssize_t ) ret ;
} else {
/* Call normal write/send */
# endif
2022-08-07 22:04:46 +00:00
return send ( mosq - > sock , buf , count , MSG_NOSIGNAL ) ;
2014-05-07 22:27:00 +00:00
# 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 ) ;
2019-07-30 14:06:55 +00:00
* sock = INVALID_SOCKET ;
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 ) ;
2019-08-01 19:46:23 +00:00
* sock = INVALID_SOCKET ;
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 ] ;
2019-12-18 16:44:26 +00:00
* pairR = INVALID_SOCKET ;
* pairW = INVALID_SOCKET ;
2014-05-07 22:27:00 +00:00
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
2020-09-10 14:50:47 +00:00
# ifndef WITH_BROKER
void * mosquitto_ssl_get ( struct mosquitto * mosq )
{
# ifdef WITH_TLS
return mosq - > ssl ;
# else
2021-08-26 09:54:03 +00:00
UNUSED ( mosq ) ;
2020-09-10 14:50:47 +00:00
return NULL ;
# endif
}
# endif