diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c
index 2dac17dc..abc03922 100644
--- a/lib/packet_mosq.c
+++ b/lib/packet_mosq.c
@@ -36,6 +36,7 @@ Contributors:
#include "read_handle.h"
#ifdef WITH_BROKER
# include "sys_tree.h"
+# include "send_mosq.h"
#else
# define G_BYTES_RECEIVED_INC(A)
# define G_BYTES_SENT_INC(A)
@@ -381,6 +382,17 @@ int packet__read(struct mosquitto *mosq)
* positive. */
mosq->in_packet.remaining_count *= -1;
+#ifdef WITH_BROKER
+ if(db->config->max_packet_size > 0 && mosq->in_packet.remaining_length+1 > db->config->max_packet_size){
+ log__printf(NULL, MOSQ_LOG_INFO, "Client %s sent too large packet %d, disconnecting.", mosq->id, mosq->in_packet.remaining_length+1);
+ if(mosq->protocol == mosq_p_mqtt5){
+ send__disconnect(mosq, MQTT_RC_PACKET_TOO_LARGE, NULL);
+ }
+ return MOSQ_ERR_OVERSIZE_PACKET;
+ }
+#else
+ // FIXME - client case for incoming message received from broker too large
+#endif
if(mosq->in_packet.remaining_length > 0){
mosq->in_packet.payload = mosquitto__malloc(mosq->in_packet.remaining_length*sizeof(uint8_t));
if(!mosq->in_packet.payload){
diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml
index 30395759..5b70e113 100644
--- a/man/mosquitto.conf.5.xml
+++ b/man/mosquitto.conf.5.xml
@@ -474,6 +474,28 @@
Reloaded on reload signal.
+
+ value
+
+ For MQTT v5 clients, it is possible to have the
+ server send a "maximum packet size" value that will
+ instruct the client it will not accept MQTT packets
+ with size greater than bytes.
+ This applies to the full MQTT packet, not just the
+ payload. Setting this option to a positive value will
+ set the maximum packet size to that number of bytes. If
+ a client sends a packet which is larger than this
+ value, it will be disconnected. This applies to all
+ clients regardless of the protocol version they are
+ using, but v3.1.1 and earlier clients will of course
+ not have received the maximum packet size information.
+ Defaults to no limit.
+ Setting below 20 bytes is forbidden because it is
+ likely to interfere with normal client operation even
+ with small payloads.
+ Reloaded on reload signal.
+
+ count
diff --git a/mosquitto.conf b/mosquitto.conf
index 550a3dd2..248417b7 100644
--- a/mosquitto.conf
+++ b/mosquitto.conf
@@ -179,6 +179,21 @@
# allowable is 65535. Do not set below 10.
#max_keepalive 65535
+
+# For MQTT v5 clients, it is possible to have the server send a "maximum packet
+# size" value that will instruct the client it will not accept MQTT packets
+# with size greater than max_packet_size bytes. This applies to the full MQTT
+# packet, not just the payload. Setting this option to a positive value will
+# set the maximum packet size to that number of bytes. If a client sends a
+# packet which is larger than this value, it will be disconnected. This applies
+# to all clients regardless of the protocol version they are using, but v3.1.1
+# and earlier clients will of course not have received the maximum packet size
+# information. Defaults to no limit. Setting below 20 bytes is forbidden
+# because it is likely to interfere with ordinary client operation, even with
+# very small payloads.
+#max_packet_size 0
+
+
# =================================================================
# Default listener
# =================================================================
diff --git a/src/conf.c b/src/conf.c
index c8d22c07..9f061cf1 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -214,6 +214,7 @@ static void config__init_reload(struct mosquitto_db *db, struct mosquitto__confi
#endif
config->log_timestamp = true;
config->max_keepalive = 65535;
+ config->max_packet_size = 0;
config->max_inflight_messages = 20;
config->persistence = false;
mosquitto__free(config->persistence_location);
@@ -1503,6 +1504,13 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
return MOSQ_ERR_INVAL;
}
config->max_keepalive = tmp_int;
+ }else if(!strcmp(token, "max_packet_size")){
+ if(conf__parse_int(&token, "max_packet_size", &tmp_int, saveptr)) return MOSQ_ERR_INVAL;
+ if(tmp_int < 20){
+ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid max_packet_size value (%d).", tmp_int);
+ return MOSQ_ERR_INVAL;
+ }
+ config->max_packet_size = tmp_int;
}else if(!strcmp(token, "max_queued_bytes")){
token = strtok_r(NULL, " ", &saveptr);
if(token){
diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h
index 7d02f432..58e7d44a 100644
--- a/src/mosquitto_broker_internal.h
+++ b/src/mosquitto_broker_internal.h
@@ -264,6 +264,7 @@ struct mosquitto__config {
FILE *log_fptr;
uint16_t max_inflight_messages;
uint16_t max_keepalive;
+ uint32_t max_packet_size;
uint32_t message_size_limit;
bool persistence;
char *persistence_location;
diff --git a/src/send_connack.c b/src/send_connack.c
index 927d4d1e..5b12bbc8 100644
--- a/src/send_connack.c
+++ b/src/send_connack.c
@@ -54,6 +54,14 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i
return rc;
}
}
+ if(db->config->max_packet_size > 0){
+ rc = mosquitto_property_add_int32(&connack_props, MQTT_PROP_MAXIMUM_PACKET_SIZE, db->config->max_packet_size);
+ if(rc){
+ mosquitto_property_free_all(&connack_props);
+ return rc;
+ }
+ }
+
/* FIXME - disable support until available */
rc = mosquitto_property_add_byte(&connack_props, MQTT_PROP_SHARED_SUB_AVAILABLE, 0);
if(rc){
diff --git a/test/broker/12-prop-maximum-packet-size-broker.py b/test/broker/12-prop-maximum-packet-size-broker.py
new file mode 100755
index 00000000..7d76d868
--- /dev/null
+++ b/test/broker/12-prop-maximum-packet-size-broker.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Check whether the broker disconnects a client nicely when they send a too large packet.
+
+from mosq_test_helper import *
+
+def write_config(filename, port):
+ with open(filename, 'w') as f:
+ f.write("port %d\n" % (port))
+ f.write("max_packet_size 30\n")
+
+port = mosq_test.get_port()
+conf_file = os.path.basename(__file__).replace('.py', '.conf')
+write_config(conf_file, port)
+
+rc = 1
+
+keepalive = 10
+connect_packet = mosq_test.gen_connect("test", proto_ver=5, keepalive=keepalive)
+props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MAXIMUM_PACKET_SIZE, 30)
+connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props)
+
+publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="0123456789012345678901234567890", proto_ver=5)
+disconnect_packet = mosq_test.gen_disconnect(reason_code=149, proto_ver=5)
+
+broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port, use_conf=True)
+
+try:
+ sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
+ mosq_test.do_send_receive(sock, publish_packet, disconnect_packet, "disconnect")
+ rc = 0
+finally:
+ broker.terminate()
+ broker.wait()
+ os.remove(conf_file)
+ (stdo, stde) = broker.communicate()
+ if rc:
+ print(stde)
+
+exit(rc)
+
diff --git a/test/broker/Makefile b/test/broker/Makefile
index 95c0458f..6901f11b 100644
--- a/test/broker/Makefile
+++ b/test/broker/Makefile
@@ -175,5 +175,6 @@ endif
./12-prop-server-keepalive.py
./12-prop-response-topic.py
./12-prop-response-topic-correlation-data.py
+ ./12-prop-maximum-packet-size-broker.py
./12-prop-maximum-packet-size-connect.py
./12-prop-maximum-packet-size-publish.py
diff --git a/test/broker/test.py b/test/broker/test.py
index e35627d6..fdef41d7 100755
--- a/test/broker/test.py
+++ b/test/broker/test.py
@@ -142,6 +142,7 @@ tests = [
(1, './12-prop-server-keepalive.py'),
(1, './12-prop-response-topic.py'),
(1, './12-prop-response-topic-correlation-data.py'),
+ (1, './12-prop-maximum-packet-size-broker.py'),
(1, './12-prop-maximum-packet-size-connect.py'),
(1, './12-prop-maximum-packet-size-publish.py'),
]