mosquitto/src/net.c

518 lines
14 KiB
C
Raw Normal View History

2014-05-07 22:27:00 +00:00
/*
Copyright (c) 2009-2015 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.
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.
Contributors:
Roger Light - initial implementation and documentation.
*/
2015-04-29 20:37:47 +00:00
#include "config.h"
2014-05-07 22:27:00 +00:00
#ifndef WIN32
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#ifdef WITH_WRAP
#include <tcpd.h>
#endif
#ifdef __FreeBSD__
# include <netinet/in.h>
# include <sys/socket.h>
#endif
#ifdef __QNX__
#include <netinet/in.h>
#include <net/netbyte.h>
#include <sys/socket.h>
#endif
2015-04-29 20:37:47 +00:00
#include "mosquitto_broker.h"
#include "mqtt3_protocol.h"
#include "memory_mosq.h"
#include "net_mosq.h"
#include "util_mosq.h"
2014-05-07 22:27:00 +00:00
#ifdef WITH_TLS
#include "tls_mosq.h"
#include <openssl/err.h>
static int tls_ex_index_context = -1;
static int tls_ex_index_listener = -1;
#endif
#include "sys_tree.h"
2014-05-07 22:27:00 +00:00
2015-05-16 17:43:06 +00:00
int net__socket_accept(struct mosquitto_db *db, int listensock)
2014-05-07 22:27:00 +00:00
{
int i;
int j;
int new_sock = -1;
struct mosquitto *new_context;
#ifdef WITH_TLS
BIO *bio;
int rc;
char ebuf[256];
unsigned long e;
#endif
#ifdef WITH_WRAP
struct request_info wrap_req;
char address[1024];
#endif
new_sock = accept(listensock, NULL, 0);
if(new_sock == INVALID_SOCKET) return -1;
G_SOCKET_CONNECTIONS_INC();
2014-05-07 22:27:00 +00:00
2015-05-18 08:29:22 +00:00
if(net__socket_nonblock(new_sock)){
2014-05-07 22:27:00 +00:00
return INVALID_SOCKET;
}
#ifdef WITH_WRAP
/* Use tcpd / libwrap to determine whether a connection is allowed. */
request_init(&wrap_req, RQ_FILE, new_sock, RQ_DAEMON, "mosquitto", 0);
fromhost(&wrap_req);
if(!hosts_access(&wrap_req)){
/* Access is denied */
if(!mosquitto__socket_get_address(new_sock, address, 1024)){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied access by tcpd.", address);
2014-05-07 22:27:00 +00:00
}
COMPAT_CLOSE(new_sock);
return -1;
2014-06-23 08:43:32 +00:00
}
2014-05-07 22:27:00 +00:00
#endif
2015-05-16 14:24:24 +00:00
new_context = context__init(db, new_sock);
2014-06-23 08:43:32 +00:00
if(!new_context){
COMPAT_CLOSE(new_sock);
return -1;
}
for(i=0; i<db->config->listener_count; i++){
for(j=0; j<db->config->listeners[i].sock_count; j++){
if(db->config->listeners[i].socks[j] == listensock){
new_context->listener = &db->config->listeners[i];
new_context->listener->client_count++;
break;
2014-05-07 22:27:00 +00:00
}
}
2014-06-23 08:43:32 +00:00
}
if(!new_context->listener){
2015-05-16 14:24:24 +00:00
context__cleanup(db, new_context, true);
2014-06-23 08:43:32 +00:00
return -1;
}
2014-05-07 22:27:00 +00:00
2014-06-23 08:43:32 +00:00
if(new_context->listener->max_connections > 0 && new_context->listener->client_count > new_context->listener->max_connections){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", new_context->address);
2015-05-16 14:24:24 +00:00
context__cleanup(db, new_context, true);
2014-06-23 08:43:32 +00:00
return -1;
}
2014-05-07 22:27:00 +00:00
#ifdef WITH_TLS
2014-06-23 08:43:32 +00:00
/* TLS init */
for(i=0; i<db->config->listener_count; i++){
for(j=0; j<db->config->listeners[i].sock_count; j++){
if(db->config->listeners[i].socks[j] == listensock){
if(db->config->listeners[i].ssl_ctx){
new_context->ssl = SSL_new(db->config->listeners[i].ssl_ctx);
if(!new_context->ssl){
2015-05-16 14:24:24 +00:00
context__cleanup(db, new_context, true);
2014-06-23 08:43:32 +00:00
return -1;
}
SSL_set_ex_data(new_context->ssl, tls_ex_index_context, new_context);
SSL_set_ex_data(new_context->ssl, tls_ex_index_listener, &db->config->listeners[i]);
new_context->want_write = true;
bio = BIO_new_socket(new_sock, BIO_NOCLOSE);
SSL_set_bio(new_context->ssl, bio, bio);
rc = SSL_accept(new_context->ssl);
if(rc != 1){
rc = SSL_get_error(new_context->ssl, rc);
if(rc == SSL_ERROR_WANT_READ){
/* We always want to read. */
}else if(rc == SSL_ERROR_WANT_WRITE){
new_context->want_write = true;
}else{
e = ERR_get_error();
while(e){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_NOTICE,
2014-06-23 08:43:32 +00:00
"Client connection from %s failed: %s.",
new_context->address, ERR_error_string(e, ebuf));
2014-05-07 22:27:00 +00:00
e = ERR_get_error();
}
2015-05-16 14:24:24 +00:00
context__cleanup(db, new_context, true);
2014-06-23 08:43:32 +00:00
return -1;
2014-05-07 22:27:00 +00:00
}
}
}
}
}
2014-06-23 08:43:32 +00:00
}
2014-05-07 22:27:00 +00:00
#endif
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s on port %d.", new_context->address, new_context->listener->port);
2014-06-23 08:43:32 +00:00
2014-05-07 22:27:00 +00:00
return new_sock;
}
#ifdef WITH_TLS
static int client_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx)
{
/* Preverify should check expiry, revocation. */
return preverify_ok;
}
#endif
#ifdef REAL_WITH_TLS_PSK
static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len)
{
struct mosquitto_db *db;
struct mosquitto *context;
2015-05-16 18:03:12 +00:00
struct mosquitto__listener *listener;
2014-05-07 22:27:00 +00:00
char *psk_key = NULL;
int len;
const char *psk_hint;
if(!identity) return 0;
db = mosquitto__get_db();
2014-05-07 22:27:00 +00:00
context = SSL_get_ex_data(ssl, tls_ex_index_context);
if(!context) return 0;
listener = SSL_get_ex_data(ssl, tls_ex_index_listener);
if(!listener) return 0;
psk_hint = listener->psk_hint;
/* The hex to BN conversion results in the length halving, so we can pass
* max_psk_len*2 as the max hex key here. */
psk_key = mosquitto__calloc(1, max_psk_len*2 + 1);
2014-05-07 22:27:00 +00:00
if(!psk_key) return 0;
if(mosquitto_psk_key_get(db, psk_hint, identity, psk_key, max_psk_len*2) != MOSQ_ERR_SUCCESS){
mosquitto__free(psk_key);
2014-05-07 22:27:00 +00:00
return 0;
}
len = mosquitto__hex2bin(psk_key, psk, max_psk_len);
2014-06-28 00:38:58 +00:00
if (len < 0){
mosquitto__free(psk_key);
2014-06-28 00:38:58 +00:00
return 0;
}
2014-05-07 22:27:00 +00:00
if(listener->use_identity_as_username){
context->username = mosquitto__strdup(identity);
2014-06-28 00:38:58 +00:00
if(!context->username){
mosquitto__free(psk_key);
2014-06-28 00:38:58 +00:00
return 0;
}
2014-05-07 22:27:00 +00:00
}
mosquitto__free(psk_key);
2014-05-07 22:27:00 +00:00
return len;
}
#endif
2014-07-03 18:33:36 +00:00
#ifdef WITH_TLS
2015-05-16 18:03:12 +00:00
static int mosquitto__tls_server_ctx(struct mosquitto__listener *listener)
2014-07-03 18:33:36 +00:00
{
int ssl_options = 0;
char buf[256];
int rc;
#ifdef WITH_EC
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L
EC_KEY *ecdh = NULL;
#endif
#endif
2014-07-03 18:33:36 +00:00
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
if(listener->tls_version == NULL){
listener->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
}else if(!strcmp(listener->tls_version, "tlsv1.2")){
listener->ssl_ctx = SSL_CTX_new(TLSv1_2_server_method());
}else if(!strcmp(listener->tls_version, "tlsv1.1")){
listener->ssl_ctx = SSL_CTX_new(TLSv1_1_server_method());
}else if(!strcmp(listener->tls_version, "tlsv1")){
listener->ssl_ctx = SSL_CTX_new(TLSv1_server_method());
}
#else
listener->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
#endif
if(!listener->ssl_ctx){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
2014-07-03 18:33:36 +00:00
return 1;
}
/* Don't accept SSLv2 or SSLv3 */
ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
#ifdef SSL_OP_NO_COMPRESSION
/* Disable compression */
ssl_options |= SSL_OP_NO_COMPRESSION;
#endif
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
/* Server chooses cipher */
ssl_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
#endif
SSL_CTX_set_options(listener->ssl_ctx, ssl_options);
#ifdef SSL_MODE_RELEASE_BUFFERS
/* Use even less memory per SSL connection. */
SSL_CTX_set_mode(listener->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
#ifdef WITH_EC
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_ecdh_auto(listener->ssl_ctx, 1);
#elif OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if(!ecdh){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS ECDH curve.");
return 1;
}
SSL_CTX_set_tmp_ecdh(listener->ssl_ctx, ecdh);
EC_KEY_free(ecdh);
#endif
#endif
2014-07-03 18:33:36 +00:00
snprintf(buf, 256, "mosquitto-%d", listener->port);
SSL_CTX_set_session_id_context(listener->ssl_ctx, (unsigned char *)buf, strlen(buf));
if(listener->ciphers){
rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, listener->ciphers);
if(rc == 0){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers);
2014-07-03 18:33:36 +00:00
return 1;
}
}else{
rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, "DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH");
if(rc == 0){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers);
2014-07-03 18:33:36 +00:00
return 1;
}
}
return MOSQ_ERR_SUCCESS;
}
#endif
2014-05-07 22:27:00 +00:00
/* Creates a socket and listens on port 'port'.
* Returns 1 on failure
* Returns 0 on success.
*/
2015-05-16 18:03:12 +00:00
int net__socket_listen(struct mosquitto__listener *listener)
2014-05-07 22:27:00 +00:00
{
int sock = -1;
struct addrinfo hints;
struct addrinfo *ainfo, *rp;
char service[10];
#ifndef WIN32
int ss_opt = 1;
#else
char ss_opt = 1;
#endif
#ifdef WITH_TLS
int rc;
X509_STORE *store;
X509_LOOKUP *lookup;
#endif
char buf[256];
if(!listener) return MOSQ_ERR_INVAL;
snprintf(service, 10, "%d", listener->port);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = PF_UNSPEC;
hints.ai_flags = AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
if(getaddrinfo(listener->host, service, &hints, &ainfo)) return INVALID_SOCKET;
listener->sock_count = 0;
listener->socks = NULL;
for(rp = ainfo; rp; rp = rp->ai_next){
if(rp->ai_family == AF_INET){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_INFO, "Opening ipv4 listen socket on port %d.", ntohs(((struct sockaddr_in *)rp->ai_addr)->sin_port));
2014-05-07 22:27:00 +00:00
}else if(rp->ai_family == AF_INET6){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_INFO, "Opening ipv6 listen socket on port %d.", ntohs(((struct sockaddr_in6 *)rp->ai_addr)->sin6_port));
2014-05-07 22:27:00 +00:00
}else{
continue;
}
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sock == -1){
strerror_r(errno, buf, 256);
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: %s", buf);
2014-05-07 22:27:00 +00:00
continue;
}
listener->sock_count++;
listener->socks = mosquitto__realloc(listener->socks, sizeof(int)*listener->sock_count);
2014-05-07 22:27:00 +00:00
if(!listener->socks){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_NOMEM;
}
listener->socks[listener->sock_count-1] = sock;
#ifndef WIN32
ss_opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ss_opt, sizeof(ss_opt));
#endif
ss_opt = 1;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ss_opt, sizeof(ss_opt));
2015-05-18 08:29:22 +00:00
if(net__socket_nonblock(sock)){
2014-05-07 22:27:00 +00:00
return 1;
}
if(bind(sock, rp->ai_addr, rp->ai_addrlen) == -1){
#ifdef WIN32
errno = WSAGetLastError();
#endif
2014-05-07 22:27:00 +00:00
strerror_r(errno, buf, 256);
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: %s", buf);
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
if(listen(sock, 100) == -1){
#ifdef WIN32
errno = WSAGetLastError();
#endif
2014-05-07 22:27:00 +00:00
strerror_r(errno, buf, 256);
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: %s", buf);
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
}
freeaddrinfo(ainfo);
/* We need to have at least one working socket. */
if(listener->sock_count > 0){
#ifdef WITH_TLS
if((listener->cafile || listener->capath) && listener->certfile && listener->keyfile){
if(mosquitto__tls_server_ctx(listener)){
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
rc = SSL_CTX_load_verify_locations(listener->ssl_ctx, listener->cafile, listener->capath);
if(rc == 0){
if(listener->cafile && listener->capath){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\" and capath \"%s\".", listener->cafile, listener->capath);
2014-05-07 22:27:00 +00:00
}else if(listener->cafile){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\".", listener->cafile);
2014-05-07 22:27:00 +00:00
}else{
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check capath \"%s\".", listener->capath);
2014-05-07 22:27:00 +00:00
}
COMPAT_CLOSE(sock);
return 1;
}
/* FIXME user data? */
if(listener->require_certificate){
SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, client_certificate_verify);
}else{
SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_NONE, client_certificate_verify);
2014-05-07 22:27:00 +00:00
}
rc = SSL_CTX_use_certificate_chain_file(listener->ssl_ctx, listener->certfile);
if(rc != 1){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server certificate \"%s\". Check certfile.", listener->certfile);
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
rc = SSL_CTX_use_PrivateKey_file(listener->ssl_ctx, listener->keyfile, SSL_FILETYPE_PEM);
if(rc != 1){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server key file \"%s\". Check keyfile.", listener->keyfile);
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
rc = SSL_CTX_check_private_key(listener->ssl_ctx);
if(rc != 1){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Server certificate/key are inconsistent.");
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
/* Load CRLs if they exist. */
if(listener->crlfile){
store = SSL_CTX_get_cert_store(listener->ssl_ctx);
if(!store){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to obtain TLS store.");
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
rc = X509_load_crl_file(lookup, listener->crlfile, X509_FILETYPE_PEM);
if(rc != 1){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load certificate revocation file \"%s\". Check crlfile.", listener->crlfile);
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
}
# ifdef REAL_WITH_TLS_PSK
}else if(listener->psk_hint){
if(tls_ex_index_context == -1){
tls_ex_index_context = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL);
}
if(tls_ex_index_listener == -1){
tls_ex_index_listener = SSL_get_ex_new_index(0, "listener", NULL, NULL, NULL);
}
if(mosquitto__tls_server_ctx(listener)){
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
SSL_CTX_set_psk_server_callback(listener->ssl_ctx, psk_server_callback);
if(listener->psk_hint){
rc = SSL_CTX_use_psk_identity_hint(listener->ssl_ctx, listener->psk_hint);
if(rc == 0){
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS PSK hint.");
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE(sock);
return 1;
}
}
# endif /* REAL_WITH_TLS_PSK */
}
#endif /* WITH_TLS */
return 0;
}else{
return 1;
}
}
2015-05-16 17:43:06 +00:00
int net__socket_get_address(int sock, char *buf, int len)
2014-05-07 22:27:00 +00:00
{
struct sockaddr_storage addr;
socklen_t addrlen;
addrlen = sizeof(addr);
if(!getpeername(sock, (struct sockaddr *)&addr, &addrlen)){
if(addr.ss_family == AF_INET){
if(inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr.s_addr, buf, len)){
return 0;
}
}else if(addr.ss_family == AF_INET6){
if(inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr.s6_addr, buf, len)){
return 0;
}
}
}
return 1;
}