- 物联网
- 消息队列
- 后端
【免费下载链接】mosquitto
Eclipse Mosquitto - An open source MQTT broker
2020 年 12 月 3 日,Eclipse Mosquitto 项目正式发布 2.0 版本。这是 Mosquitto 历史上一次带有破坏性行为变更(breaking changes)的大版本升级,broker 的安全默认值、监听器行为、权限模型与插件接口均发生了根本性变化。本文以官方 2.0.0 发布公告为主线,结合当前仓库源码(src/)、动态安全插件(plugins/dynamic-security/)与配置解析实现,逐项解析新特性、破坏性变更的底层逻辑、客户端库与命令行工具的新能力,并给出从 1.x 迁移到 2.0 时的实操要点。读完本文,你将能够理解 2.0 默认安全模型的工作原理、正确配置监听器与鉴权、使用动态安全插件与mosquitto_ctrl控制运行中的 broker,并掌握新插件接口与命令行客户端的新增选项。
一、2.0.0 发布概览:一次"更安全默认值"的硬升级
发布公告开宗明义地指出:2.0 是一版"big change",对 broker 存在破坏性行为变更,用户、发行版打包者与插件作者都应参考从 1.x 迁移到 2.0 的指南。迁移指南在仓库中没有单独成文,但官方公告列出的关键变更都可以在当前仓库源码中找到对应实现,本文后续章节会逐条给出源码佐证。
2.0 的核心设计理念可以概括为三点:
- 安全默认:不再依赖旧版"默认宽松"的行为,broker 要求用户主动决策如何配置安全策略,同时更快地放弃特权(privileged access)。
- 新插件接口:在原有认证与访问控制插件接口之上,提供能力更强、更易开发和扩展的插件体系,同时保持对既有插件的兼容(编译时需使用 2.0 头文件)。
- 开箱即用的动态安全:内置新的动态安全插件,提供基于客户端(client)、组(group)、角色(role)的认证与访问控制,配置通过特殊主题在线管理、可热更新。
此外,broker 在高客户端数场景下的性能得到改进;新增mosquitto_ctrl工具用于控制运行中的 broker;bridge(桥接)开始支持 MQTT v5;命令行客户端获得一批小改进。
二、破坏性变更详解:升级前必须知道的行为差异
2.1 无监听器配置时默认只绑定回环地址
这是 2.0 最影响部署习惯的变更。当 broker没有配置任何 listener启动时,将只绑定到回环接口127.0.0.1和/或::1,即只有本机客户端可以连接。具体行为:
- 直接运行
mosquitto或mosquitto -p 1883:绑定回环接口。 - 使用不含任何 listener 的配置文件运行:绑定回环接口的 1883 端口。
- 配置文件中定义了 listener:默认绑定
0.0.0.0/::(所有接口),仍可显式绑定指定地址。 - 若以
mosquitto -c mosquitto.conf -p 1884运行,且配置文件中已定义 listener,则命令行-p指定的端口会被忽略,不会为其创建监听器。
该逻辑在源码中有明确实现。listeners__start()在 src/listeners.c#L228-L244 中判断db.config->local_only:为真时调用listeners__start_local_only(),在 src/listeners.c#L181-L225 中向127.0.0.1与::1的 1883 端口(或命令行-p指定的端口)各添加一个监听器,并打印警告:
Starting in local only mode. Connections will only be possible from clients running on this machine. Create a configuration file which defines a listener to allow remote access.而local_only标志由配置解析驱动:config->local_only = true是 src/conf.c#L251 中的默认值,一旦配置文件中出现 listener 定义,src/conf.c#L1166、src/conf.c#L1705、src/conf.c#L2102 等位置会将其置为false。
迁移要点:若需要远程访问,必须显式创建配置文件并定义 listener,例如:
listener 1883 0.0.0.02.2 所有监听器默认allow_anonymous false
2.0 中所有 listener 的匿名访问默认被禁用,除非在配置文件中显式设置allow_anonymous true。这意味着配置 listener 时,用户必须二选一:配置某种认证与访问控制方法,或显式开启匿名。唯一例外是 broker 在未配置 listener 的"本地模式"下运行时,匿名连接被允许(因为只监听回环,风险可控)。
该逻辑在配置读取的收尾阶段实现。config__read()在 src/conf.c#L740-L756 中:
- 若
local_only == true,直接设置allow_anonymous = true; - 否则,在
per_listener_settings模式下遍历各 listener,把仍处于未显式设置状态(-1)的 listener 的allow_anonymous置为false;非 per-listener 模式下则把全局默认置为false。
配置文件语法示例:
listener 1883 0.0.0.0 allow_anonymous false password_file /etc/mosquitto/passwd2.3 root 启动时更早地放弃特权
在类 Unix 系统上以 root 运行 Mosquitto 时,2.0 在读取配置文件之后立即尝试降权,而不是像旧版那样等到 listener(及 TLS 证书)和日志启动之后才降权。带来的后果:
- 除非用户显式(且不推荐)配置以 root 运行,客户端将永远无法连接到以 root 运行的 broker;
- broker 需要访问的所有路径(配置文件、持久化文件、日志、TLS 证书等)都必须对降权后的非特权用户可读;
- 使用 Let's Encrypt 证书的用户需要额外处理,使 Mosquitto 能访问证书文件,仓库提供了示例部署续期钩子脚本 misc/letsencrypt/mosquitto-copy.sh;
- 降权目标用户按可用性依次为:配置文件中指定的用户、
mosquitto、nobody。
降权实现位于 src/mosquitto.c#L130-L219 的drop_privileges():它在geteuid() == 0时执行setgid/setuid,若配置的用户不存在则回退到nobody(src/mosquitto.c#L181-L191),并支持 Docker 常见的PUID/PGID环境变量映射(src/mosquitto.c#L146-L177);在 Snap 环境下(环境变量SNAP_NAME为mosquitto)则跳过降权(src/mosquitto.c#L140-L144)。调用时机位于 src/mosquitto.c#L390,即配置读取之后、listener 启动之前。
迁移要点:以 root 安装运行时,请确认以下路径对mosquitto用户可读(必要时可写):配置文件、持久化文件目录、日志目录、TLS 证书与私钥、pid_file路径。
2.4pid_file总是写入
pid_file选项现在无论是否使用-d参数,都会尝试写入 pid 文件。对应实现为pid__write()(src/mosquitto.c#L260-L275),它在db.config->pid_file非空时无条件执行fopen并写入进程号。
2.5tls_version语义:从"精确版本"改为"最低版本"
tls_version选项从指定精确TLS 协议版本,改为指定最低允许的 TLS 协议版本(对应 GitHub issue #1258)。也就是说,设置tls_version tlsv1.2表示允许 TLS 1.2 及更高版本,而不是强制恰好使用 TLS 1.2。该选项在 src/conf.c#L2310-L2314 中解析(bridge_tls_version在 src/conf.c#L1457),且不支持热重载(reload 时被跳过)。
2.6max_queued_messages默认值提升并覆盖 QoS 0
max_queued_messages默认值从 100 提高到 1000(对应 issue #1258 之外的 #265 相关讨论),并且当客户端在线时也适用于 QoS 0 消息。默认值在 src/conf.c#L305 中设置(config->max_queued_messages = 1000),解析逻辑在 src/conf.c#L1989-L1992。其生效逻辑可在 src/database.c#L60-L133 中看到:在计算入队配额时区分在线(inflight)与离线(queued)两条路径,src/handle_publish.c#L354 在out_packet_count >= max_queued_messages时拒绝继续入队。
2.7 客户端默认加载系统 CA 证书
mosquitto_sub、mosquitto_pub、mosquitto_rr在使用-L mqtts://...时,或端口设为 8883 且未加载其他 CA 证书时,默认加载操作系统提供的 CA 证书(对应 issue #1824)。
2.8 依赖要求
最低支持的 libwebsockets 版本提升到 2.4.0。
三、新插件接口:更强能力、更低开发门槛
2.0 引入了超越原有认证/ACL 插件接口的新插件体系。新接口在保留旧插件兼容性的同时,提供了更多插件能力。从仓库源码可以看到,2.0 的插件事件处理已经按功能拆分到独立文件,包括:
- src/plugin_auth.c、src/plugin_acl_check.c:认证与 ACL 检查;
- src/plugin_message.c:消息收发钩子;
- src/plugin_subscribe.c、src/plugin_unsubscribe.c:订阅/退订钩子;
- src/plugin_connect.c、src/plugin_disconnect.c:连接生命周期事件;
- src/plugin_persist.c、src/plugin_tick.c:持久化与周期性 tick;
- src/plugin_psk_key.c、src/plugin_extended_auth.c:PSK 密钥与扩展认证。
插件 API 定义可参考 include/mosquitto_broker.h 与 include/mosquitto_plugin.h。仓库中的插件示例集中在 plugins/examples/,覆盖了按环境变量鉴权(auth-by-env)、按 IP 鉴权(auth-by-ip)、按主题限制(topic-jail)、消息载荷修改(payload-modification)、连接状态事件(connection-state)、延迟认证(delayed-auth)等常见场景,是学习新插件接口的最佳起点。
四、动态安全插件:客户端/组/角色的在线访问控制
2.0 内置了一个全新的动态安全插件,位于 plugins/dynamic-security/,提供基于客户端、组、角色的认证与访问控制。其核心特点:
- 配置在线管理:通过特殊的
$CONTROL主题以 JSON 命令形式下发配置,broker 运行期间可随时更新; - 灵活直接:为 broker 访问控制提供灵活且直观的配置方式;
- 默认角色:插件初始化时会预置两个管理角色——
broker-admin(授予管理 broker 通用配置的$CONTROL/broker/#权限)与dynsec-admin(授予管理客户端/组/角色的$CONTROL/dynamic-security/#权限),见 plugins/dynamic-security/config_init.c#L508-L509; - $CONTROL 主题保护:ACL 检查逻辑对
$CONTROL前缀主题不做"fall through"放行,必须显式授权(plugins/dynamic-security/acl.c#L244-L245)。
官方 README(plugins/dynamic-security/README.md)说明:JSON 命令发布到类似$CONTROL/<feature>/v1的主题。仓库还提供了完整的测试套件 test/broker/14-dynsec-*.py,覆盖默认访问、匿名组、客户端/组/角色管理、ACL、通配符、禁用客户端、配置初始化等场景,可作为理解插件行为的活文档。
五、mosquitto_ctrl:控制运行中的 broker
新增工具mosquitto_ctrl(源码在 apps/mosquitto_ctrl/)用于控制运行中的 broker。2.0 中它的能力局限于控制动态安全插件(对应子命令 apps/mosquitto_ctrl/dynsec.c、apps/mosquitto_ctrl/dynsec_client.c 等),后续版本会扩展到更多功能。典型用法是与动态安全插件配合,通过$CONTROL/dynamic-security/v1主题执行createClient、createRole、createGroup、setClientPermissions等 JSON 管理命令。
六、Broker 新特性详解
6.1 桥接(Bridge)能力增强
- MQTT v5 支持:bridge 开始支持 MQTT v5;
bridge_outgoing_retain:允许完全禁用桥接出站消息的 retain 位,在桥接到 Amazon、Google 等不允许 retain 的平台时非常有用。解析见 src/conf.c#L1309-L1312;- MQTT v5 retain-available 属性:处理 v5 桥中"retain-available"为 false 的情形;
- 协议回退:允许 MQTT v5.0 出站桥在连接仅支持 v3.x 的 broker 时回退到 MQTT v3.1.1;
bridge_max_packet_size(issue #265):限制桥接消息包大小,解析见 src/conf.c#L1287-L1290;bridge_bind_address(issue #1311):为桥接连接指定绑定地址,解析见 src/conf.c#L1226-L1229;- v5 属性遵循:bridge 遵循 MQTT v5 的 server-keepalive,并支持 maximum-qos 属性。
6.2 TLS 与密码学
ciphers_tls1.3(issue #1825):允许设置 TLS 1.3 加密套件,解析见 src/conf.c#L1506-L1512;- 证书加载方式变更:启用基于证书的 TLS 加密现在通过
certfile和keyfile,而不是capath或cafile; - SIGHUP 重载证书:服务端 TLS 证书在收到 SIGHUP 信号时会重新加载;
- PBKDF2-SHA512:密码哈希新增 PBKDF2-SHA512 支持,对应实现可参考 common/password_mosq.c。
6.3 运行与监听
- Unix domain socket 监听器:支持 Unix 域套接字作为 listener;
- 降权回退:以 root 运行时,若降权到
mosquitto用户失败,则尝试nobody,减轻自行安装用户的负担; - DLT 日志:
log_dest dlt可在运行时配置(issue #1735); - receive-maximum:broker 在 MQTT v5 CONNACK 中发送 receive-maximum 属性;
- deny ACL 类型(issue #1611):ACL 新增
deny类型,可显式拒绝; - per_listener 持久化修复:修复了重载持久化文件且启用
per_listener_settings true时 listener 与客户端关联丢失的问题(issue #1891)。
6.4 新增插件 API 函数
mosquitto_plugin_publish():插件可直接发布消息;mosquitto_client_protocol_version():插件可判断客户端使用的 MQTT 协议版本;mosquitto_kick_client_by_clientid()/mosquitto_kick_client_by_username():插件可主动断开客户端;- 支持在插件中处理
$CONTROL/主题; - v5 插件 ACL 检查支持控制 UNSUBSCRIBE 调用。
七、Broker 修复要点
- 对无效的 PUBLISH、SUBSCRIBE、UNSUBSCRIBE 包发送带
malformed-packet原因码的 DISCONNECT; - 明确
mosquitto_client_certificate()使用后必须调用X509_free()(issue #1842); - 修复桥接 socket 出错时未从 socket 哈希表移除的问题(issue #1897);
mosquitto_passwd现在禁止密码中包含:字符(issue #1833);- 修复
log_timestamp_format不适用于log_dest topic的问题(issue #1862); - 修复 Windows 上插件加载失败时的崩溃(issue #1866)与 Windows 文件日志问题(issue #1880);
- 配置文件指向目录时报错(issue #1814);
- 修复
notifications_local_only true时 bridge 错误设置 Will 以管理远端通知的问题(issue #1902); - 新连接日志现在记录客户端端口(issue #1911)。
八、客户端库(libmosquitto)特性与修复
8.1 特性
- 客户端 ID 生成策略变更(issue #291):客户端不再为 v3.1.1 连接生成随机 client id,改由 broker 生成(与 v5 行为一致);
- Unix domain socket:支持通过 Unix 域套接字连接 broker;
- 属性 API:新增
mosquitto_property_identifier()、mosquitto_property_identifier_to_string()、mosquitto_property_next(),用于获取属性整数标识、转换属性名、遍历属性列表; MOSQ_OPT_TCP_NODELAY(issue #1526):允许禁用 Nagle 算法;mosquitto_ssl_get():客户端可取得 SSL 结构做额外校验;MOSQ_OPT_BIND_ADDRESS:可独立于mosquitto_connect*()设置绑定地址;MOSQ_OPT_TLS_USE_OS_CERTS:指示客户端加载并信任操作系统提供的 CA 证书。
8.2 修复
- 修复重连时发送配额(send quota)被错误重置(issue #1822);
- 在日志互斥锁初始化前不再使用日志(issue #1819);
- 修复 OS X 上缺失
mach/mach_time.h头文件(issue #1831); - 修复自动重连时未发送 CONNECT 属性(issue #1846)。
九、命令行客户端(mosquitto_pub / mosquitto_sub / mosquitto_rr)新能力
9.1 通用能力
--version:所有客户端支持输出版本号;--nodelay:启用MOSQ_OPT_TCP_NODELAY;-x:便捷设置 MQTT v5 的 session-expiry-interval 属性;--tls-use-os-certs:显式使用操作系统 CA 证书;- Unix 域套接字:通过
--unix参数连接; - 超时返回码 27(issue #275):
mosquitto_sub -W <secs>与mosquitto_rr -W <secs>超时后返回 27。
9.2 JSON 输出
- 使用 cJSON 库生成 JSON 输出(可用时)(issue #1222);
mosquitto_sub/mosquitto_rr的 JSON 输出支持 MQTT v5 属性信息(issue #1416);- 新增
--pretty选项,控制 JSON 输出是否格式化; - 非 JSON 模式下也支持 v5 属性打印。
9.3 mosquitto_sub 专属改进
- 固定列宽输出:支持字段宽度与精度的格式说明符,便于对齐表格化输出;
--random-filter:按比例随机过滤打印收到的消息,便于在不逐条查看的情况下观察主题整体行为;- 时间戳格式:
%j与%J时间戳改为 ISO 8601 兼容格式。
9.4 修复
mosquitto_sub在全部订阅被拒绝时退出;mosquitto_pub使用-f发送 0 长度文件不再报错;- 修复
mosquitto_rr中-e与-t参数的描述(issue #1881); mosquitto_sub在 Windows 上使用%U选项时以错误退出而非静默退出(issue #1908)。
十、从 1.x 迁移到 2.0 的检查清单
综合官方发布公告与上文源码分析,从 1.x 升级到 2.0 时应按如下顺序核查:
- 监听器:无 listener 的配置默认只监听回环接口;远程访问必须显式配置 listener;命令行
-p与配置文件 listener 同时存在时命令行端口被忽略。 - 匿名访问:所有 listener 默认拒绝匿名连接,需配置认证/ACL 或显式
allow_anonymous true。 - 权限与路径:root 启动会在读取配置后立即降权(依次尝试配置用户、
mosquitto、nobody),确保证书、持久化文件、日志等对非特权用户可访问;Let's Encrypt 证书可参考 misc/letsencrypt/mosquitto-copy.sh。 - TLS:
tls_version语义变为"最低版本";证书启用改走certfile/keyfile;libwebsockets 最低版本升至 2.4.0。 - 队列与持久化:
max_queued_messages默认 1000 且覆盖在线 QoS 0;pid_file无论是否-d都会写入。 - 插件:既有插件需用 2.0 头文件重新编译并核对新接口;新项目建议直接使用动态安全插件或按 plugins/examples/ 的新接口编写。
- 客户端:客户端不再为 v3.1.1 生成随机 client id;CA 证书默认加载策略变化,注意
--tls-use-os-certs与MOSQ_OPT_TLS_USE_OS_CERTS的使用。
完整的版本变更历史可进一步查阅仓库根目录的 ChangeLog.txt,动态安全插件的配置命令与示例见 plugins/dynamic-security/README.md,相应的集成测试可参考 test/broker/14-dynsec-acl.py 等用例。在动手升级前,建议先在测试环境用 2.0 配置逐项验证上述行为,再应用到生产 broker。
- 物联网
- 消息队列
- 后端
【免费下载链接】mosquitto
Eclipse Mosquitto - An open source MQTT broker
相关推荐
Eclipse Mosquitto 2.0.0 发布深度解析:安全默认值、v5 插件体系与动态安全插件
Eclipse Mosquitto 2.0.0 发布深度解析:安全默认值、v5 插件体系与动态安全插件 Mosquitto 2.0 是该项目历史上一次里程碑式的
后端消息队列消息路由Eclipse Mosquitto 2.0 发布深度解读:安全默认值、新插件体系与 MQTT v5 桥接能力
Eclipse Mosquitto 2.0 发布深度解读:安全默认值、新插件体系与 MQTT v5 桥接能力 Eclipse Mosquitto 2.0 是该项
物联网消息队列后端网络/通信OpenClaw 项目愿景与技术路线图解析:安全默认、插件分层与配置迁移策略
OpenClaw 项目愿景与技术路线图解析:安全默认、插件分层与配置迁移策略 OpenClaw 是一个真正"动手做事"(actually does things
AI 应用AI Agent交互助手后端即时通讯网关
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考