Add `accept_protocol_versions` option.

pull/2386/head
Roger A. Light 4 years ago
parent f552ec48b1
commit ba936a869d

@ -58,8 +58,10 @@ Broker:
- Add `mosquitto_client_port()` function for plugins.
- Add `global_max_clients` option to allow limiting client sessions globally
on the broker.
- Add `global_max_connections` option to allow limiting client onnections globally
- Add `global_max_connections` option to allow limiting client connections globally
on the broker.
- Add `accept_protocol_versions` option to allow limiting which MQTT protocol
versions are allowed for a particular listener.
Client library:
- Add MOSQ_OPT_DISABLE_SOCKETPAIR to allow the disabling of the socketpair

@ -1138,6 +1138,29 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S
<refsect2>
<title>General Options</title>
<variablelist>
<varlistentry>
<term><option>accepted_protocol_versions</option> <replaceable>versions</replaceable></term>
<listitem>
<para>
Accepted protocol versions. This sets what versions
of the MQTT protocol will be accepted on this
listener. Can be any combination of 3, 4, 5 in a
comma separated list, e.g.
</para>
<programlisting>
# Allow v5.0 only:
listener 1883
accept_protocol_versions 5
# Allow v3.1 and v3.1.1:
listener 1884
accept_protocol_versions 3, 4</programlisting>
<para>
Defaults to allowing all versions.
</para>
<para>Reloaded on reload signal.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>bind_address</option> <replaceable>address</replaceable></term>
<listitem>

@ -296,6 +296,21 @@
# cafile, certfile, keyfile, ciphers, and ciphers_tls13 options are supported.
#protocol mqtt
# Accepted protocol versions. This sets what versions of the MQTT protocol will
# be accepted on this listener. Can be any combination of 3, 4, 5 in a comma
# separated list, e.g.
#
# # Allow v5.0 only:
# listener 1883
# accept_protocol_versions 5
#
# # Allow v3.1 and v3.1.1:
# listener 1884
# accept_protocol_versions 3, 4
#
# Defaults to allowing all versions.
#accept_protocol_versions 3,4,5
# Set use_username_as_clientid to true to replace the clientid that a client
# connected with with its username. This allows authentication to be tied to
# the clientid, which means that it is possible to prevent one client

@ -826,7 +826,31 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload,
}
token = strtok_r((*buf), " ", &saveptr);
if(token){
if(!strcmp(token, "acl_file")){
if(!strcmp(token, "accept_protocol_version")){
if(cur_listener == &config->default_listener){
log__printf(NULL, MOSQ_LOG_ERR, "Error: You must define a listener before using he %s option.", "accept_protocol_version");
return MOSQ_ERR_INVAL;
}
cur_listener->disable_protocol_v3 = true;
cur_listener->disable_protocol_v4 = true;
cur_listener->disable_protocol_v5 = true;
if(saveptr == NULL){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty %s value in configuration.", "accept_protocol_version");
return MOSQ_ERR_INVAL;
}
token = strtok_r(saveptr, ", \t", &saveptr);
while(token){
if(!strcmp(token, "3")){
cur_listener->disable_protocol_v3 = false;
}else if(!strcmp(token, "4")){
cur_listener->disable_protocol_v4 = false;
}else if(!strcmp(token, "5")){
cur_listener->disable_protocol_v5 = false;
}
token = strtok_r(NULL, ", \t", &saveptr);
}
}else if(!strcmp(token, "acl_file")){
conf__set_cur_security_options(config, cur_listener, &cur_security_options);
if(reload){
mosquitto__free(cur_security_options->acl_file);

@ -434,6 +434,19 @@ error_cleanup:
}
static int check_protocol_version(struct mosquitto__listener *listener, int protocol_version)
{
if((protocol_version == 3 && listener->disable_protocol_v3 == false)
|| (protocol_version == 4 && listener->disable_protocol_v4 == false)
|| (protocol_version == 5 && listener->disable_protocol_v5 == false)
){
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_NOT_SUPPORTED;
}
}
int handle__connect(struct mosquitto *context)
{
@ -503,6 +516,17 @@ int handle__connect(struct mosquitto *context)
rc = MOSQ_ERR_PROTOCOL;
goto handle_connect_error;
}
if(check_protocol_version(context->listener, protocol_version)){
if(protocol_version == 3 || protocol_version == 4){
context->protocol = mosq_p_mqtt311;
send__connack(context, 0, CONNACK_REFUSED_PROTOCOL_VERSION, NULL);
}else{
context->protocol = mosq_p_mqtt5;
send__connack(context, 0, MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION, NULL);
}
rc = MOSQ_ERR_NOT_SUPPORTED;
goto handle_connect_error;
}
if(!strcmp(protocol_name, PROTOCOL_NAME_v31)){
if((protocol_version&0x7F) != PROTOCOL_VERSION_v31){
if(db.config->connection_messages == true){

@ -243,6 +243,9 @@ struct mosquitto__listener {
#ifdef WITH_UNIX_SOCKETS
char *unix_socket_path;
#endif
bool disable_protocol_v3;
bool disable_protocol_v4;
bool disable_protocol_v5;
};

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# Test accept_protocol_version option
from mosq_test_helper import *
def write_config(filename, port, accept):
with open(filename, 'w') as f:
f.write("listener %s\n" % (port))
f.write("allow_anonymous true\n")
f.write("accept_protocol_version %s\n" % (accept))
def do_test(accept, expect_success):
port = mosq_test.get_port()
conf_file = os.path.basename(__file__).replace('.py', '.conf')
write_config(conf_file, port, accept)
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
try:
for proto_ver in [3, 4, 5]:
rc = 1
connect_packet = mosq_test.gen_connect("accept-protocol-test-%d" % (proto_ver), proto_ver=proto_ver)
if proto_ver == 5:
if proto_ver in expect_success:
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver)
else:
connack_packet = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION, proto_ver=proto_ver, properties=None)
else:
if proto_ver in expect_success:
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver)
else:
connack_packet = mosq_test.gen_connack(rc=1, proto_ver=proto_ver)
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
sock.close()
rc = 0
except mosq_test.TestError:
pass
finally:
if write_config is not None:
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(accept="3,4,5", expect_success=[3, 4, 5])
do_test(accept="5,4,3", expect_success=[3, 4, 5])
do_test(accept="3 ,4, 5", expect_success=[3, 4, 5])
do_test(accept=" , 3 , 4 , 5 ", expect_success=[3, 4, 5])
do_test(accept="3", expect_success=[3])
do_test(accept="4", expect_success=[4])
do_test(accept="5", expect_success=[5])
do_test(accept="3,4", expect_success=[3, 4])
do_test(accept="3,5", expect_success=[3, 5])
do_test(accept="4,3", expect_success=[3, 4])
do_test(accept="4,5", expect_success=[4, 5])
do_test(accept="5,3", expect_success=[3, 5])

@ -24,6 +24,7 @@ msg_sequence_test:
01 :
./01-connect-575314.py
./01-connect-accept-protocol.py
./01-connect-allow-anonymous.py
./01-connect-disconnect-v5.py
./01-connect-global-max-clients.py

@ -6,6 +6,7 @@ import ptest
tests = [
#(ports required, 'path'),
(1, './01-connect-575314.py'),
(1, './01-connect-accept-protocol.py'),
(1, './01-connect-allow-anonymous.py'),
(1, './01-connect-disconnect-v5.py'),
(1, './01-connect-global-max-clients.py'),

Loading…
Cancel
Save