Merge branch 'fixes'

This commit is contained in:
Roger A. Light 2021-03-11 22:35:31 +00:00
commit c03c6b765e
28 changed files with 353 additions and 280 deletions

View File

@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0042 NEW)
project(mosquitto)
set (VERSION 2.0.8)
set (VERSION 2.0.9)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/")

View File

@ -1,3 +1,39 @@
2.0.9 - 2021-03-11
==================
Security:
- If an empty or invalid CA file was provided to the client library for
verifying the remote broker, then the initial connection would fail but
subsequent connections would succeed without verifying the remote broker
certificate. Closes #2130.
- If an empty or invalid CA file was provided to the broker for verifying the
remote broker for an outgoing bridge connection then the initial connection
would fail but subsequent connections would succeed without verifying the
remote broker certificate. Closes #2130.
Broker:
- Fix encrypted bridge connections incorrectly connecting when `bridge_cafile`
is empty or invalid. Closes #2130.
- Fix `tls_version` behaviour not matching documentation. It was setting the
exact TLS version to use, not the minimium TLS version to use. Closes #2110.
- Fix messages to `$` prefixed topics being rejected. Closes #2111.
- Fix QoS 0 messages not being delivered when max_queued_bytes was configured.
Closes #2123.
- Fix bridge increasing backoff calculation.
- Improve handling of invalid combinations of listener address and bind
interface configurations. Closes #2081.
- Fix `max_keepalive` option not applying to clients connecting with keepalive
set to 0. Closes #2117.
Client library:
- Fix encrypted connections incorrectly connecting when the CA file passed to
`mosquitto_tls_set()` is empty or invalid. Closes #2130.
- Fix connections retrying very rapidly in some situations.
Build:
- Fix cmake epoll detection.
2.0.8 - 2021-02-25
==================

View File

@ -127,7 +127,7 @@ WITH_XTREPORT=no
# Also bump lib/mosquitto.h, CMakeLists.txt,
# installer/mosquitto.nsi, installer/mosquitto64.nsi
VERSION=2.0.8
VERSION=2.0.9
# Client library SO version. Bump if incompatible API/ABI changes are made.
SOVERSION=1

View File

@ -66,7 +66,7 @@ extern "C" {
#define LIBMOSQUITTO_MAJOR 2
#define LIBMOSQUITTO_MINOR 0
#define LIBMOSQUITTO_REVISION 8
#define LIBMOSQUITTO_REVISION 9
/* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */
#define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION)
@ -1604,40 +1604,6 @@ libmosq_EXPORT int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt
*/
libmosq_EXPORT int mosquitto_void_option(struct mosquitto *mosq, enum mosq_opt_t option, void *value);
/*
* Function: mosquitto_string_option
*
* Used to set const char* options for the client.
*
* Parameters:
* mosq - a valid mosquitto instance.
* option - the option to set.
* value - the option specific value.
*
* Options:
* MOSQ_OPT_TLS_ENGINE
* Configure the client for TLS Engine support. Pass a TLS Engine ID
* to be used when creating TLS connections.
* Must be set before <mosquitto_connect>.
* MOSQ_OPT_TLS_KEYFORM
* Configure the client to treat the keyfile differently depending
* on its type. Must be set before <mosquitto_connect>.
* Set as either "pem" or "engine", to determine from where the
* private key for a TLS connection will be obtained. Defaults to
* "pem", a normal private key file.
* MOSQ_OPT_TLS_KPASS_SHA1
* Where the TLS Engine requires the use of a password to be
* accessed, this option allows a hex encoded SHA1 hash of the
* private key password to be passed to the engine directly.
* Must be set before <mosquitto_connect>.
* MOSQ_OPT_TLS_ALPN
* If the broker being connected to has multiple services available
* on a single TLS port, such as both MQTT and WebSockets, use this
* option to configure the ALPN option for the connection.
*/
libmosq_EXPORT int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, const char *value);
/*
* Function: mosquitto_reconnect_delay_set
*

View File

@ -9,7 +9,7 @@
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
Name "Eclipse Mosquitto"
!define VERSION 2.0.8
!define VERSION 2.0.9
OutFile "mosquitto-${VERSION}-install-windows-x86.exe"
InstallDir "$PROGRAMFILES\mosquitto"

View File

@ -9,7 +9,7 @@
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
Name "Eclipse Mosquitto"
!define VERSION 2.0.8
!define VERSION 2.0.9
OutFile "mosquitto-${VERSION}-install-windows-x64.exe"
!include "x64.nsh"

View File

@ -203,6 +203,13 @@ static int interruptible_sleep(struct mosquitto *mosq, time_t reconnect_delay)
char pairbuf;
int maxfd = 0;
#ifndef WIN32
if(read(mosq->sockpairR, &pairbuf, 1) == 0){
}
#else
recv(mosq->sockpairR, &pairbuf, 1, 0);
#endif
local_timeout.tv_sec = reconnect_delay;
#ifdef HAVE_PSELECT
local_timeout.tv_nsec = 0;

View File

@ -196,6 +196,7 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_st
#ifdef WITH_TLS
mosq->ssl = NULL;
mosq->ssl_ctx = NULL;
mosq->ssl_ctx_defaults = true;
mosq->tls_cert_reqs = SSL_VERIFY_PEER;
mosq->tls_insecure = false;
mosq->want_write = false;

View File

@ -190,8 +190,8 @@ struct mosquitto_msg_data{
#ifdef WITH_BROKER
struct mosquitto_client_msg *inflight;
struct mosquitto_client_msg *queued;
unsigned long msg_bytes;
unsigned long msg_bytes12;
long msg_bytes;
long msg_bytes12;
int msg_count;
int msg_count12;
#else

View File

@ -632,7 +632,7 @@
<option>31</option>, or the more verbose
<option>mqttv5</option>, <option>mqttv311</option>, or
<option>mqttv31</option>.
Defaults to <option>311</option>.</para>
Defaults to <option>5</option>.</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -2,7 +2,7 @@
MAJOR=2
MINOR=0
REVISION=8
REVISION=9
sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk

View File

@ -1,5 +1,5 @@
name: mosquitto
version: 2.0.8
version: 2.0.9
summary: Eclipse Mosquitto MQTT broker
description: This is a message broker that supports version 5.0, 3.1.1, and 3.1 of the MQTT
protocol.

View File

@ -77,6 +77,11 @@ if (WITH_BUNDLED_DEPS)
include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/deps)
endif (WITH_BUNDLED_DEPS)
find_path(HAVE_SYS_EPOLL_H sys/epoll.h)
if (HAVE_SYS_EPOLL_H)
add_definitions("-DWITH_EPOLL")
endif()
option(INC_BRIDGE_SUPPORT
"Include bridge support for connecting to other brokers?" ON)
if (INC_BRIDGE_SUPPORT)

View File

@ -112,6 +112,7 @@ int bridge__new(struct mosquitto__bridge *bridge)
new_context->tls_alpn = new_context->bridge->tls_alpn;
new_context->tls_engine = db.config->default_listener.tls_engine;
new_context->tls_keyform = db.config->default_listener.tls_keyform;
new_context->ssl_ctx_defaults = true;
#ifdef FINAL_WITH_TLS_PSK
new_context->tls_psk_identity = new_context->bridge->tls_psk_identity;
new_context->tls_psk = new_context->bridge->tls_psk;
@ -313,10 +314,8 @@ int bridge__connect_step3(struct mosquitto *context)
rc = send__connect(context, context->keepalive, context->clean_start, NULL);
if(rc == MOSQ_ERR_SUCCESS){
bridge__backoff_reset(context);
return MOSQ_ERR_SUCCESS;
}else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){
bridge__backoff_reset(context);
return MOSQ_ERR_SUCCESS;
}else{
if(rc == MOSQ_ERR_TLS){
@ -454,10 +453,8 @@ int bridge__connect(struct mosquitto *context)
rc2 = send__connect(context, context->keepalive, context->clean_start, NULL);
if(rc2 == MOSQ_ERR_SUCCESS){
bridge__backoff_reset(context);
return rc;
}else if(rc2 == MOSQ_ERR_ERRNO && errno == ENOTCONN){
bridge__backoff_reset(context);
return MOSQ_ERR_SUCCESS;
}else{
if(rc2 == MOSQ_ERR_TLS){
@ -562,6 +559,8 @@ int bridge__on_connect(struct mosquitto *context)
}
}
bridge__backoff_reset(context);
return MOSQ_ERR_SUCCESS;
}
@ -646,11 +645,11 @@ void bridge__packet_cleanup(struct mosquitto *context)
packet__cleanup(&(context->in_packet));
}
static int rand_between(int base, int cap)
static int rand_between(int low, int high)
{
int r;
util__random_bytes(&r, sizeof(int));
return (r % (cap - base)) + base;
return (abs(r) % (high - low)) + low;
}
static void bridge__backoff_step(struct mosquitto *context)
@ -685,6 +684,33 @@ static void bridge__backoff_reset(struct mosquitto *context)
}
}
static void bridge_check_pending(struct mosquitto *context)
{
int err;
socklen_t len;
if(context->state == mosq_cs_connect_pending){
len = sizeof(int);
if(!getsockopt(context->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &len)){
if(err == 0){
mosquitto__set_state(context, mosq_cs_new);
#if defined(WITH_ADNS) && defined(WITH_BRIDGE)
if(context->bridge){
bridge__connect_step3(context);
}
#endif
}else if(err == ECONNREFUSED){
do_disconnect(context, MOSQ_ERR_CONN_LOST);
return;
}
}else{
do_disconnect(context, MOSQ_ERR_CONN_LOST);
return;
}
}
}
void bridge_check(void)
{
static time_t last_check = 0;
@ -703,6 +729,7 @@ void bridge_check(void)
if(context->sock != INVALID_SOCKET){
mosquitto__check_keepalive(context);
bridge_check_pending(context);
/* Check for bridges that are not round robin and not currently
* connected to their primary broker. */

View File

@ -53,7 +53,7 @@ bool db__ready_for_flight(struct mosquitto_msg_data *msgs, int qos)
if(db.config->max_queued_messages == 0 && db.config->max_inflight_bytes == 0){
return true;
}
valid_bytes = msgs->msg_bytes - db.config->max_inflight_bytes < db.config->max_queued_bytes;
valid_bytes = ((msgs->msg_bytes - (ssize_t)db.config->max_inflight_bytes) < (ssize_t)db.config->max_queued_bytes);
valid_count = msgs->msg_count - msgs->inflight_maximum < db.config->max_queued_messages;
if(db.config->max_queued_messages == 0){
@ -90,8 +90,8 @@ bool db__ready_for_queue(struct mosquitto *context, int qos, struct mosquitto_ms
{
int source_count;
int adjust_count;
size_t source_bytes;
size_t adjust_bytes = db.config->max_inflight_bytes;
long source_bytes;
ssize_t adjust_bytes = (ssize_t)db.config->max_inflight_bytes;
bool valid_bytes;
bool valid_count;
@ -893,6 +893,26 @@ int db__message_reconnect_reset(struct mosquitto *context)
}
int db__message_remove_incoming(struct mosquitto* context, uint16_t mid)
{
struct mosquitto_client_msg *tail, *tmp;
if(!context) return MOSQ_ERR_INVAL;
DL_FOREACH_SAFE(context->msgs_in.inflight, tail, tmp){
if(tail->mid == mid) {
if(tail->store->qos != 2){
return MOSQ_ERR_PROTOCOL;
}
db__message_remove(&context->msgs_in, tail);
return MOSQ_ERR_SUCCESS;
}
}
return MOSQ_ERR_NOT_FOUND;
}
int db__message_release_incoming(struct mosquitto *context, uint16_t mid)
{
struct mosquitto_client_msg *tail, *tmp;

View File

@ -244,7 +244,9 @@ int connect__on_authorised(struct mosquitto *context, void *auth_data_out, uint1
goto error;
}
}
if(context->keepalive > db.config->max_keepalive){
if(db.config->max_keepalive &&
(context->keepalive > db.config->max_keepalive || context->keepalive == 0)){
context->keepalive = db.config->max_keepalive;
if(mosquitto_property_add_int16(&connack_props, MQTT_PROP_SERVER_KEEP_ALIVE, context->keepalive)){
rc = MOSQ_ERR_NOMEM;

View File

@ -285,6 +285,18 @@ int handle__publish(struct mosquitto *context)
if(msg->qos > 0){
db__message_store_find(context, msg->source_mid, &stored);
}
if(stored && msg->source_mid != 0 &&
(stored->qos != msg->qos
|| stored->payloadlen != msg->payloadlen
|| strcmp(stored->topic, msg->topic)
|| memcmp(stored->payload, msg->payload, msg->payloadlen) )){
log__printf(NULL, MOSQ_LOG_WARNING, "Reused message ID %u from %s detected. Clearing from storage.", msg->source_mid, context->id);
db__message_remove_incoming(context, msg->source_mid);
stored = NULL;
}
if(!stored){
if(msg->qos == 0
|| db__ready_for_flight(&context->msgs_in, msg->qos)

View File

@ -642,6 +642,7 @@ int persist__restore(void);
int db__message_count(int *count);
int db__message_delete_outgoing(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_state expect_state, int qos);
int db__message_insert(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, uint8_t qos, bool retain, struct mosquitto_msg_store *stored, mosquitto_property *properties, bool update);
int db__message_remove_incoming(struct mosquitto* context, uint16_t mid);
int db__message_release_incoming(struct mosquitto *context, uint16_t mid);
int db__message_update_outgoing(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_state state, int qos);
void db__message_dequeue_first(struct mosquitto *context, struct mosquitto_msg_data *msg_data);

View File

@ -335,14 +335,14 @@ int net__tls_server_ctx(struct mosquitto__listener *listener)
}else if(!strcmp(listener->tls_version, "tlsv1.3")){
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
}else if(!strcmp(listener->tls_version, "tlsv1.2")){
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_3);
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
}else if(!strcmp(listener->tls_version, "tlsv1.1")){
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3);
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
#else
}else if(!strcmp(listener->tls_version, "tlsv1.2")){
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
}else if(!strcmp(listener->tls_version, "tlsv1.1")){
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2);
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
#endif
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unsupported tls_version \"%s\".", listener->tls_version);
@ -624,23 +624,44 @@ static int net__bind_interface(struct mosquitto__listener *listener, struct addr
&& ifa->ifa_addr->sa_family == rp->ai_addr->sa_family){
if(rp->ai_addr->sa_family == AF_INET){
memcpy(&((struct sockaddr_in *)rp->ai_addr)->sin_addr,
&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
sizeof(struct in_addr));
if(listener->host &&
memcmp(&((struct sockaddr_in *)rp->ai_addr)->sin_addr,
&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
sizeof(struct in_addr))){
freeifaddrs(ifaddr);
return MOSQ_ERR_SUCCESS;
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface address for %s does not match specified listener address (%s).",
listener->bind_interface, listener->host);
return MOSQ_ERR_INVAL;
}else{
memcpy(&((struct sockaddr_in *)rp->ai_addr)->sin_addr,
&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
sizeof(struct in_addr));
freeifaddrs(ifaddr);
return MOSQ_ERR_SUCCESS;
}
}else if(rp->ai_addr->sa_family == AF_INET6){
memcpy(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr,
&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
sizeof(struct in6_addr));
freeifaddrs(ifaddr);
return MOSQ_ERR_SUCCESS;
if(listener->host &&
memcmp(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr,
&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
sizeof(struct in6_addr))){
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface address for %s does not match specified listener address (%s).",
listener->bind_interface, listener->host);
return MOSQ_ERR_INVAL;
}else{
memcpy(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr,
&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
sizeof(struct in6_addr));
freeifaddrs(ifaddr);
return MOSQ_ERR_SUCCESS;
}
}
}
}
freeifaddrs(ifaddr);
log__printf(NULL, MOSQ_LOG_ERR, "Error: Interface %s not found.", listener->bind_interface);
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface %s does not support %s configuration.",
listener->bind_interface, rp->ai_addr->sa_family == AF_INET ? "IPv4" : "IPv6");
return MOSQ_ERR_NOT_FOUND;
}
#endif
@ -654,6 +675,9 @@ static int net__socket_listen_tcp(struct mosquitto__listener *listener)
char service[10];
int rc;
int ss_opt = 1;
#ifndef WIN32
bool interface_bound = false;
#endif
if(!listener) return MOSQ_ERR_INVAL;
@ -718,12 +742,14 @@ static int net__socket_listen_tcp(struct mosquitto__listener *listener)
#ifndef WIN32
if(listener->bind_interface){
/* It might be possible that an interface does not support all relevant sa_families.
* We should successfully find at least one. */
if(net__bind_interface(listener, rp)){
COMPAT_CLOSE(sock);
freeaddrinfo(ainfo);
mosquitto__free(listener->socks);
return 1;
listener->sock_count--;
continue;
}
interface_bound = true;
}
#endif
@ -745,6 +771,13 @@ static int net__socket_listen_tcp(struct mosquitto__listener *listener)
}
freeaddrinfo(ainfo);
#ifndef WIN32
if(listener->bind_interface && !interface_bound){
mosquitto__free(listener->socks);
return 1;
}
#endif
return 0;
}

View File

@ -83,7 +83,10 @@ int retain__store(const char *topic, struct mosquitto_msg_store *stored, char **
assert(split_topics);
HASH_FIND(hh, db.retains, split_topics[0], strlen(split_topics[0]), retainhier);
if(retainhier == NULL) return MOSQ_ERR_NOT_FOUND;
if(retainhier == NULL){
retainhier = retain__add_hier_entry(NULL, &db.retains, split_topics[0], (uint16_t)strlen(split_topics[0]));
if(!retainhier) return MOSQ_ERR_NOMEM;
}
for(i=0; split_topics[i] != NULL; i++){
slen = strlen(split_topics[i]);

View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
from mosq_test_helper import *
def write_config(filename, port):
with open(filename, 'w') as f:
f.write("listener %d\n" % (port))
f.write("allow_anonymous true\n")
f.write("max_inflight_messages 20\n")
f.write("max_inflight_bytes 1000000\n")
f.write("max_queued_messages 20\n")
f.write("max_queued_bytes 1000000\n")
def do_test(proto_ver):
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("subpub-qos0-bytes", keepalive=keepalive, proto_ver=proto_ver)
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver)
connect_packet_helper = mosq_test.gen_connect("qos0-bytes-helper", keepalive=keepalive, proto_ver=proto_ver)
mid = 1
subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos0/queued/bytes", 1, proto_ver=proto_ver)
suback_packet = mosq_test.gen_suback(mid, 1, proto_ver=proto_ver)
publish_packet0 = mosq_test.gen_publish("subpub/qos0/queued/bytes", qos=0, payload="message", proto_ver=proto_ver)
port = mosq_test.get_port()
conf_file = os.path.basename(__file__).replace('.py', '.conf')
write_config(conf_file, port)
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=4, port=port, connack_error="connack 1")
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
helper = mosq_test.do_client_connect(connect_packet_helper, connack_packet, timeout=4, port=port, connack_error="connack helper")
helper.send(publish_packet0)
mosq_test.expect_packet(sock, "publish0", publish_packet0)
rc = 0
sock.close()
except mosq_test.TestError:
pass
finally:
os.remove(conf_file)
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde.decode('utf-8'))
print("proto_ver=%d" % (proto_ver))
exit(rc)
do_test(proto_ver=4)
do_test(proto_ver=5)
exit(0)

View File

@ -1,71 +0,0 @@
#!/usr/bin/env python3
# Test whether a SUBSCRIBE to a topic with QoS 2 results in the correct SUBACK packet.
from mosq_test_helper import *
def helper(port):
connect_packet = mosq_test.gen_connect("test-helper", keepalive=60)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 128
publish_packet = mosq_test.gen_publish("qos1/timeout/test", qos=1, mid=mid, payload="timeout-message")
puback_packet = mosq_test.gen_puback(mid)
sock = mosq_test.do_client_connect(connect_packet, connack_packet, connack_error="helper connack")
mosq_test.do_send_receive(sock, publish_packet, puback_packet, "helper puback")
sock.close()
def do_test(proto_ver):
rc = 1
mid = 3265
keepalive = 60
connect_packet = mosq_test.gen_connect("pub-qos1-timeout-test", keepalive=keepalive, proto_ver=proto_ver)
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver)
subscribe_packet = mosq_test.gen_subscribe(mid, "qos1/timeout/test", 1, proto_ver=proto_ver)
suback_packet = mosq_test.gen_suback(mid, 1, proto_ver=proto_ver)
mid = 1
publish_packet = mosq_test.gen_publish("qos1/timeout/test", qos=1, mid=mid, payload="timeout-message", proto_ver=proto_ver)
publish_dup_packet = mosq_test.gen_publish("qos1/timeout/test", qos=1, mid=mid, payload="timeout-message", dup=True, proto_ver=proto_ver)
puback_packet = mosq_test.gen_puback(mid, proto_ver=proto_ver)
port = mosq_test.get_port()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
helper(port)
# Should have now received a publish command
mosq_test.expect_packet(sock, "publish", publish_packet)
# Wait for longer than 5 seconds to get republish with dup set
# This is covered by the 8 second timeout
mosq_test.expect_packet(sock, "dup publish", publish_dup_packet)
sock.send(puback_packet)
rc = 0
sock.close()
except mosq_test.TestError:
pass
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde.decode('utf-8'))
print("proto_ver=%d" % (proto_ver))
exit(rc)
do_test(proto_ver=4)
do_test(proto_ver=5)
exit(0)

View File

@ -1,81 +0,0 @@
#!/usr/bin/env python3
# Test whether a SUBSCRIBE to a topic with QoS 2 results in the correct SUBACK packet.
from mosq_test_helper import *
def helper(port):
connect_packet = mosq_test.gen_connect("test-helper", keepalive=60)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 312
publish_packet = mosq_test.gen_publish("qos2/timeout/test", qos=2, mid=mid, payload="timeout-message")
pubrec_packet = mosq_test.gen_pubrec(mid)
pubrel_packet = mosq_test.gen_pubrel(mid)
pubcomp_packet = mosq_test.gen_pubcomp(mid)
sock = mosq_test.do_client_connect(connect_packet, connack_packet, connack_error="helper connack")
mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "helper pubrec")
mosq_test.do_send_receive(sock, pubrel_packet, pubcomp_packet, "helper pubcomp")
sock.close()
def do_test(proto_ver):
rc = 1
mid = 3265
keepalive = 60
connect_packet = mosq_test.gen_connect("pub-qo2-timeout-test", keepalive=keepalive, proto_ver=proto_ver)
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver)
subscribe_packet = mosq_test.gen_subscribe(mid, "qos2/timeout/test", 2, proto_ver=proto_ver)
suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=proto_ver)
mid = 1
publish_packet = mosq_test.gen_publish("qos2/timeout/test", qos=2, mid=mid, payload="timeout-message", proto_ver=proto_ver)
publish_dup_packet = mosq_test.gen_publish("qos2/timeout/test", qos=2, mid=mid, payload="timeout-message", dup=True, proto_ver=proto_ver)
pubrec_packet = mosq_test.gen_pubrec(mid, proto_ver=proto_ver)
pubrel_packet = mosq_test.gen_pubrel(mid, proto_ver=proto_ver)
pubcomp_packet = mosq_test.gen_pubcomp(mid, proto_ver=proto_ver)
port = mosq_test.get_port()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
helper(port)
# Should have now received a publish command
mosq_test.expect_packet(sock, "publish", publish_packet)
# Wait for longer than 5 seconds to get republish with dup set
# This is covered by the 8 second timeout
mosq_test.expect_packet(sock, "dup publish", publish_dup_packet)
mosq_test.do_send_receive(sock, pubrec_packet, pubrel_packet, "pubrel")
# Wait for longer than 5 seconds to get republish with dup set
# This is covered by the 8 second timeout
mosq_test.expect_packet(sock, "dup pubrel", pubrel_packet)
sock.send(pubcomp_packet)
rc = 0
sock.close()
except mosq_test.TestError:
pass
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde.decode('utf-8'))
print("proto_ver=%d" % (proto_ver))
exit(rc)
do_test(proto_ver=4)
do_test(proto_ver=5)
exit(0)

View File

@ -1,52 +0,0 @@
#!/usr/bin/env python3
# Test whether a PUBLISH to a topic with QoS 2 results in the correct packet
# flow. This test introduces delays into the flow in order to force the broker
# to send duplicate PUBREC and PUBCOMP messages.
from mosq_test_helper import *
def do_test(port):
rc = 1
keepalive = 600
connect_packet = mosq_test.gen_connect("pub-qos2-timeout-test", keepalive=keepalive, proto_ver=proto_ver)
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver)
mid = 1926
publish_packet = mosq_test.gen_publish("pub/qos2/test", qos=2, mid=mid, payload="timeout-message", proto_ver=proto_ver)
pubrec_packet = mosq_test.gen_pubrec(mid, proto_ver=proto_ver)
pubrel_packet = mosq_test.gen_pubrel(mid, proto_ver=proto_ver)
pubcomp_packet = mosq_test.gen_pubcomp(mid, proto_ver=proto_ver)
port = mosq_test.get_port()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet)
mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "pubrec")
# Timeout is 8 seconds which means the broker should repeat the PUBREC.
mosq_test.expect_packet(sock, "pubrec", pubrec_packet)
mosq_test.do_send_receive(sock, pubrel_packet, pubcomp_packet, "pubcomp")
rc = 0
sock.close()
except mosq_test.TestError:
pass
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde.decode('utf-8'))
print("proto_ver=%d" % (proto_ver))
exit(rc)
do_test(proto_ver=4)
do_test(proto_ver=5)
exit(0)

View File

@ -45,6 +45,7 @@ test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 13 14
./02-subhier-crash.py
./02-subpub-qos0-long-topic.py
./02-subpub-qos0-oversize-payload.py
./02-subpub-qos0-queued-bytes.py
./02-subpub-qos0-retain-as-publish.py
./02-subpub-qos0-send-retain.py
./02-subpub-qos0-subscription-id.py

View File

@ -28,6 +28,7 @@ tests = [
(1, './02-subhier-crash.py'),
(1, './02-subpub-qos0-long-topic.py'),
(1, './02-subpub-qos0-oversize-payload.py'),
(1, './02-subpub-qos0-queued-bytes.py'),
(1, './02-subpub-qos0-retain-as-publish.py'),
(1, './02-subpub-qos0-send-retain.py'),
(1, './02-subpub-qos0-subscription-id.py'),

View File

@ -1,7 +1,7 @@
<!--
.. title: Download
.. slug: download
.. date: 2022-02-25 17:18:38 UTC
.. date: 2022-03-11 22:16:38 UTC
.. tags: tag
.. category: category
.. link: link
@ -11,7 +11,7 @@
# Source
* [mosquitto-2.0.8.tar.gz](https://mosquitto.org/files/source/mosquitto-2.0.8.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-2.0.8.tar.gz.asc))
* [mosquitto-2.0.9.tar.gz](https://mosquitto.org/files/source/mosquitto-2.0.9.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-2.0.9.tar.gz.asc))
* [Git source code repository](https://github.com/eclipse/mosquitto) (github.com)
Older downloads are available at [https://mosquitto.org/files/](../files/)
@ -24,8 +24,8 @@ distributions.
## Windows
* [mosquitto-2.0.8-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-2.0.8-install-windows-x64.exe) (64-bit build, Windows Vista and up, built with Visual Studio Community 2019)
* [mosquitto-2.0.8-install-windows-x32.exe](https://mosquitto.org/files/binary/win32/mosquitto-2.0.8-install-windows-x86.exe) (32-bit build, Windows Vista and up, built with Visual Studio Community 2019)
* [mosquitto-2.0.9-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-2.0.9-install-windows-x64.exe) (64-bit build, Windows Vista and up, built with Visual Studio Community 2019)
* [mosquitto-2.0.9-install-windows-x32.exe](https://mosquitto.org/files/binary/win32/mosquitto-2.0.9-install-windows-x86.exe) (32-bit build, Windows Vista and up, built with Visual Studio Community 2019)
Older installers can be found at [https://mosquitto.org/files/binary/](https://mosquitto.org/files/binary/).

View File

@ -0,0 +1,101 @@
<!--
.. title: Version 2.0.9 released.
.. slug: version-2-0-9-released
.. date: 2021-03-11 22:19:38 UTC
.. tags: Releases
.. category:
.. link:
.. description:
.. type: text
-->
Versions 2.0.9, 1.6.14, and 1.5.11 of Mosquitto have been released. These are
bugfix releases and include a minor security fix.
# 2.0.9
## Security
- If an empty or invalid CA file was provided to the client library for
verifying the remote broker, then the initial connection would fail but
subsequent connections would succeed without verifying the remote broker
certificate. Closes [#2130].
- If an empty or invalid CA file was provided to the broker for verifying the
remote broker for an outgoing bridge connection then the initial connection
would fail but subsequent connections would succeed without verifying the
remote broker certificate. Closes [#2130].
## Broker
- Fix encrypted bridge connections incorrectly connecting when `bridge_cafile`
is empty or invalid. Closes [#2130].
- Fix `tls_version` behaviour not matching documentation. It was setting the
exact TLS version to use, not the minimium TLS version to use. Closes [#2110].
- Fix messages to `$` prefixed topics being rejected. Closes [#2111].
- Fix QoS 0 messages not being delivered when max_queued_bytes was configured.
Closes [#2123].
- Fix bridge increasing backoff calculation.
- Improve handling of invalid combinations of listener address and bind
interface configurations. Closes [#2081].
- Fix `max_keepalive` option not applying to clients connecting with keepalive
set to 0. Closes [#2117].
## Client library
- Fix encrypted connections incorrectly connecting when the CA file passed to
`mosquitto_tls_set()` is empty or invalid. Closes [#2130].
- Fix connections retrying very rapidly in some situations.
## Build
- Fix cmake epoll detection.
# 1.6.14
## Security
- If an empty or invalid CA file was provided to the client library for
verifying the remote broker, then the initial connection would fail but
subsequent connections would succeed without verifying the remote broker
certificate. Closes [#2130].
- If an empty or invalid CA file was provided to the broker for verifying the
remote broker for an outgoing bridge connection then the initial connection
would fail but subsequent connections would succeed without verifying the
remote broker certificate. Closes [#2130].
## Broker
- Fix encrypted bridge connections incorrectly connecting when `bridge_cafile`
is empty or invalid. Closes [#2130].
## Client library
- Fix encrypted connections incorrectly connecting when the CA file passed to
`mosquitto_tls_set()` is empty or invalid. Closes [#2130].
- Fix connections retrying very rapidly in some situations.
## Clients
- Fix possible loss of data in `mosquitto_pub -l` when sending multiple long
lines. Closes [#2078].
# 1.5.11
## Security
- If an empty or invalid CA file was provided to the client library for
verifying the remote broker, then the initial connection would fail but
subsequent connections would succeed without verifying the remote broker
certificate. Closes [#2130].
- If an empty or invalid CA file was provided to the broker for verifying the
remote broker for an outgoing bridge connection then the initial connection
would fail but subsequent connections would succeed without verifying the
remote broker certificate. Closes [#2130].
## Broker
- Fix encrypted bridge connections incorrectly connecting when `bridge_cafile`
is empty or invalid. Closes [#2130].
## Client library
- Fix encrypted connections incorrectly connecting when the CA file passed to
`mosquitto_tls_set()` is empty or invalid. Closes [#2130].
[#2040]: https://github.com/eclipse/mosquitto/issues/2040
[#2078]: https://github.com/eclipse/mosquitto/issues/2078
[#2081]: https://github.com/eclipse/mosquitto/issues/2081
[#2110]: https://github.com/eclipse/mosquitto/issues/2110
[#2111]: https://github.com/eclipse/mosquitto/issues/2111
[#2117]: https://github.com/eclipse/mosquitto/issues/2117
[#2123]: https://github.com/eclipse/mosquitto/issues/2123
[#2130]: https://github.com/eclipse/mosquitto/issues/2130