news 2026/9/14 4:31:26

ZeroTierOne 内置 hiredis 1.0.2 版本演进解析:从 CVE-2021-32765 安全修复到 RESP3、SSL 与分配器注入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ZeroTierOne 内置 hiredis 1.0.2 版本演进解析:从 CVE-2021-32765 安全修复到 RESP3、SSL 与分配器注入

ZeroTierOne 内置 hiredis 1.0.2 版本演进解析:从 CVE-2021-32765 安全修复到 RESP3、SSL 与分配器注入

【免费下载链接】ZeroTierOneA Smart Ethernet Switch for Earth项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTierOne

导读

本文以 ZeroTierOne 仓库中随附的 hiredis 1.0.2 版本(ext/hiredis-1.0.2/CHANGELOG.md)为核心,梳理该 C 语言 Redis 客户端从 0.10 到 1.0.2 的关键版本演进脉络,重点解读 1.0.0 稳定版引入的 RESP3、SSL/TLS 连接、运行时分配器注入、独立连接/命令超时等新特性,以及 1.0.1/1.0.2 针对 CVE-2021-32765 的安全修复与 SONAME 回退事件。文章结合仓库内 hiredis 源码(ext/hiredis-1.0.2/hiredis.h)、适配器(ext/hiredis-1.0.2/adapters/)、示例(ext/hiredis-1.0.2/examples/)以及 ZeroTierOne 中央控制器对 Redis 的实际使用方式(nonfree/controller/),帮助读者理解 hiredis 的 API 变迁、升级注意事项,以及它如何在 ZeroTierOne 的控制器集群场景中发挥作用。

一、hiredis 是什么,为什么 ZeroTierOne 会随附它

hiredis 是一款极简风格的 C 语言 Redis 客户端库:它只提供对 Redis 协议的最小支持,却通过 printf 风格的命令格式化 API 提供了远比其代码量所暗示的更高层的使用体验。它不针对每条 Redis 命令提供显式绑定,而是把"构造命令 + 解析回复"两件事做到极致,并附带一套与 I/O 层完全解耦的流式回复解析器,可以复用于各类高层语言绑定的高效回复解析。

ZeroTierOne 在ext/目录下随附了多个版本的 hiredis 及其上层 C++ 封装 redis-plus-plus:

  • ext/hiredis-0.14.1/:1.0.0 之前的 0.14.1 版本;
  • ext/hiredis-1.0.2/:本文章核心版本,包含完整的 hiredis 1.0.2 源码树;
  • ext/redis-plus-plus-1.1.1/ 与 ext/redis-plus-plus-1.3.3/:基于 hiredis 的 C++ 封装。

按照 ext/README.md 的说明,ext/子目录存放的是"在系统不提供这些库的平台上,被编译进二进制文件的捆绑第三方库"以及预编译二进制。也就是说,hiredis 在这里扮演的是 ZeroTierOne 中央控制器(Central Controller)在本地系统缺少该库时可直接编译链接的兜底依赖。ZeroTierOne 的中央控制器在实现基于 Redis 的流(Stream)通知、发布订阅与状态写入时,实际使用的是 redis-plus-plus 这一 C++ 封装(其底层正是 hiredis),例如 nonfree/controller/RedisListener.cpp 中通过sw::redis::Redis/sw::redis::RedisClusterxreadxdel消费 Redis Stream,并通过RedisConfig(见 nonfree/controller/Redis.hpp)中的hostnameportpasswordclusterMode配置连接。

因此,hiredis 的版本选择直接影响 ZeroTierOne 控制器在 Ubuntu 22.04、CentOS 8 等目标平台上能否稳定、安全地对接 Redis,本文对 1.0.2 版本变更的解读,对理解该依赖选型具有直接参考价值。

二、版本时间线与 1.0.2 的定位

结合 ext/hiredis-1.0.2/CHANGELOG.md 可以还原 hiredis 从 0.10 到 1.0.2 的完整演进时间线:

版本发布日期定位与关键内容
1.0.22021-10-07修复 CVE-2021-32765,同时把 SONAME 回退到正确的1.0.0
1.0.12021-10-04安全修复版,修复 CVE-2021-32765,但错误地提升了 SONAME(官方明确建议改用 1.0.2)
1.0.02020-08-03首个稳定版,引入 RESP3、SSL 连接、分配器注入、独立超时、更好的 Windows 支持
1.0.0-rc12020-07-29与 1.0.0 之间无代码差异,直接参见 1.0.0 变更说明
0.14.12020-03-13安全补丁版,加入安全分配包装(CVE-2020-7105)
0.14.02018-09-25redisReply.len改为size_t、长度溢出防护、移除旧宏别名、DEBUG更名DEBUG_FLAGS
0.13.x2015修复异步回复处理内存泄漏、增加多种事件适配器、引入 Windows 兼容层
0.12.x2015KeepAlive、libuv 适配器、IPv6、redisConnectFd()/redisFreeKeepFd()
0.11.x最大 multi-bulk 深度提升到 7、读缓冲从 2k 提升到 16k、改用 poll(2)
0.10.xMakefile 重构、修复若干内存泄漏

需要特别注意的是 1.0.1 与 1.0.2 之间的关系:1.0.1 是安全修复版,本应修复 CVE-2021-32765,但它错误地提升了库的 SONAME(共享库版本标识);1.0.2 则是"1.0.0 加上 CVE-2021-32765 修复,除此之外完全相同"的版本,并把 SONAME 回退到正确的1.0.0。因此 changelog 中明确以红色标注:不要使用 1.0.1,请使用 1.0.2。从仓库源码可以印证这一点:ext/hiredis-1.0.2/include/hiredis/hiredis.h 中同时定义了HIREDIS_MAJOR 1HIREDIS_MINOR 0HIREDIS_PATCH 2HIREDIS_SONAME 1.0.0,即代码版本是 1.0.2,而 SONAME 保持为 1.0.0——这正是 1.0.2 版本的核心修正。

2.1 安全背景:CVE-2021-32765

CVE-2021-32765 由 Microsoft Security Vulnerability Research 发现,修复提交来自 Yossi Gottlieb(commit 76a7b100,该提交在仓库内体现为 hiredis 1.0.2 源码树相对于 1.0.0 的唯一功能差异)。由于 1.0.2 与 1.0.0 仅在安全修复这一点上不同,任何使用 hiredis 1.0.0 且通过 SSL/TLS 访问 Redis 的部署,都建议升级到 1.0.2 以获得该修复。

三、1.0.0 稳定版的四项核心能力

1.0.0 是 hiredis 历史上第一个稳定版,changelog 明确列出了四大新特性:RESP3 协议支持、SSL/TLS 连接、运行时分配器注入、更好的 Windows 支持,此外还引入了独立的连接超时与命令超时。以下结合仓库源码逐项展开。

3.1 RESP3:面向 Redis 6 的新协议支持

RESP3 是 Redis 6 引入的回复协议,相比 RESP2 增加了多种数据类型。hiredis 1.0.0 通过 #697、#805、#819、#841 等 PR 将 RESP3 支持从 Redis 移植到 hiredis,并在 ext/hiredis-1.0.2/include/hiredis/hiredis.h 的redisReply结构中落地:新增double dval字段承载双精度浮点值、char vtype[4]承载 verbatim 字符串的 3 字符内容类型(如"txt"),同时size_t len记录字符串长度、char *str统一承载 ERROR、STRING、VERB、DOUBLE 等类型的字符串表示。

RESP3 新增的回复类型包括:

  • REDIS_REPLY_DOUBLE:双精度浮点数,值以字符串形式保存在str中,可用strtod等转换;
  • REDIS_REPLY_BOOL:布尔值,保存在integer成员中(01);
  • REDIS_REPLY_MAP:元素数恒为偶数的数组,功能上与REDIS_REPLY_ARRAY等价;
  • REDIS_REPLY_SET:元素唯一的数组;
  • REDIS_REPLY_PUSH:Redis 可自发产生的数组,至少包含两个子元素,第一个是 PUSH 类型(如messageinvalidate),第二个是 PUSH 载荷子数组;
  • REDIS_REPLY_ATTR:结构与 MAP 相同、用于携带回复元数据的类型(截至 Redis 6.0.6 尚未实际使用);
  • REDIS_REPLY_BIGNUM:任意大整数,以字符串形式保存在str中;
  • REDIS_REPLY_VERB:verbatim 字符串,载荷在str中,类型信息在vtype中。

与 RESP3 强相关的是 PUSH 消息处理。Redis 6 引入的 PUSH 回复(协议符号>)可以随时自发到达,因此必须用回调方式处理。1.0.0 的默认行为是在redisContextredisAsyncContext上安装默认处理器,自动拦截并释放 PUSH 回复,保证升级到 Redis 6 + RESP3 后存量代码无需改动即可工作。仓库中的 ext/hiredis-1.0.2/examples/example-push.c 就是展示自定义 PUSH 处理器用法的官方示例。需要自定义行为时,有两种方式:

  1. redisOptions中设置push_cb(同步)或async_push_cb(异步),并用redisConnectWithOptions/redisAsyncConnectWithOptions建立连接;
  2. 连接建立后调用redisSetPushCallback/redisAsyncSetPushCallback动态设置。

这两类回调都会返回当前已配置的处理器,便于覆盖后再恢复原值。如果希望 hiredis 完全不自动拦截、释放 PUSH 回复(例如用于 MONITOR 或 SUBSCRIBE 这类阻塞式redisGetReply循环),可以设置REDIS_OPT_NO_PUSH_AUTOFREE标志(该标志定义于 ext/hiredis-1.0.2/include/hiredis/hiredis.h,值为0x08)并将回调置空,或在连接后调用redisSetPushCallback(context, NULL)。注意:无处理器时,一次redisCommand可能产生多条回复,仅适用于阻塞式读取场景。

3.2 SSL/TLS 连接支持

1.0.0 通过 #645、#699、#702、#708、#711、#821 等 PR 完整引入 SSL 支持,并在 #821 中用新的 SSL API 取代了旧的redisSecureConnection()

构建时需显式启用(默认关闭):

make USE_SSL=1

这要求系统具备 OpenSSL 开发包(包含头文件)。启用后,SSL 支持被打入独立的libhiredis_ssl.a/libhiredis_ssl.so库,原始libhiredis不受影响,因此不会给不用的用户引入额外依赖。使用侧需要额外包含hiredis_ssl.h,并链接libhiredis_ssllibhiredis-lssl -lcrypto

hiredis 的 SSL 实现建立在普通redisContext/redisAsyncContext之上:先建立 TCP 连接,再发起 SSL/TLS 握手。仓库提供了 ext/hiredis-1.0.2/hiredis_ssl.h 以及配套示例 ext/hiredis-1.0.2/examples/example-ssl.c 和 ext/hiredis-1.0.2/examples/example-libevent-ssl.c,后者演示了 SSL 与 libevent 适配器组合使用的方式。初始化有两种路径:

  1. 直接使用 OpenSSL API 初始化全局状态并自行创建SSL_CTX */SSL *,然后用redisInitiateSSL()完成握手;
  2. 使用 hiredis 提供的封装redisSSLContext持有配置(可跨多个上下文复用),调用redisCreateSSLContext()创建、redisInitiateSSLWithContext()完成握手。

典型的封装式用法为:先redisInitOpenSSL()初始化全局 OpenSSL 状态(仅在应用其他位置未初始化时调用一次),再redisCreateSSLContext()依次传入 CA 证书包文件、可信证书目录、客户端证书文件、客户端私钥文件、SNI 服务器名(均可选),出错时通过redisSSLContextGetError(ssl_error)获取错误描述;随后redisConnect()建立普通连接并检查err,最后redisInitiateSSLWithContext()协商 TLS。

3.3 运行时分配器注入

1.0.0 通过 #800 引入运行时分配器注入(allocator injection),并在 #824 中补充了文档与测试。hiredis 使用一组定义于 ext/hiredis-1.0.2/alloc.h 的函数指针结构(hiredisAllocFuncs)持有当前配置的分配/释放函数,默认指向 libc 的malloccallocreallocstrdupfree。该特性同时解决了 #769(undefined reference to hi_malloc)这一困扰定制分配场景的问题——所有分配统一走包装层,OOM 等情形可在包装函数内统一处理。

覆盖方式如下:

hiredisAllocFuncs myfuncs = { .mallocFn = my_malloc, .callocFn = my_calloc, .reallocFn = my_realloc, .strdupFn = my_strdup, .freeFn = my_free, }; /* 覆盖分配器(函数返回当前分配器,便于保存与恢复) */ hiredisAllocFuncs orig = hiredisSetAllocators(&myfuncs); /* 恢复为默认 libc 函数 */ hiredisResetAllocators();

在 ZeroTierOne 中,该机制为控制器对接自研内存管理或内存统计(例如 nonfree/controller/ 中依赖 jemalloc 的场景)提供了干净的接入点。

3.4 更完善的 Windows 支持

通过 #652(MinGW 支持)与 #663(Windows CI)等 PR,1.0.0 显著改善了 Windows 支持,后续又有多轮修复(如 #845 改用_WIN32宏、#846 的 Windows 质量改进、#848 的 MinGW 编译修复)。仓库 ext/hiredis-1.0.2/appveyor.yml 保留了 Windows 持续集成配置,ext/hiredis-1.0.2/win32.h 与 ext/hiredis-1.0.2/sockcompat.c/ext/hiredis-1.0.2/sockcompat.h 提供了 BSD socket 与 WSA API 差异的兼容层。

值得注意的还有redisFD类型在 Windows 与 Unix 上的差异:在 Unix 上redisFD是普通intREDIS_INVALID_FD-1),在 Windows 上则是SOCKET(32 位unsigned long或 64 位unsigned long longREDIS_INVALID_FD为全 1),这一点已内建在 ext/hiredis-1.0.2/include/hiredis/hiredis.h 的宏定义中,跨平台代码可直接使用redisFDREDIS_INVALID_FD而无需关心平台差异。

四、1.0.0 的破坏性变更与升级指南

4.1redisOptions超时字段拆分

1.0.0 将原先单一的options->timeout拆分为两个字段:

  • connect_timeout:连接超时;
  • command_timeout:命令超时。

旧代码中所有使用options->timeout的地方都必须改为options->connect_timeout(或按语义改用command_timeout)。这一变更源自 #722(redisConnectWithOptions不应设置命令超时)与 #829。在 ext/hiredis-1.0.2/include/hiredis/hiredis.h 的redisOptions结构中,两个字段并列定义,且command_timeout可在运行时通过redisSetTimeout/redisAsyncSetTimeout更新,这一点也写入了头文件注释。

4.2 协议长度校验收紧

Bulk 与 multi-bulk 的长度小于-1或大于LLONG_MAX现在被视为协议错误,这与 RESP 规范保持一致;在 32 位平台上,上限进一步降低为SIZE_MAX。这一规则在 0.14.0 已经引入(源自 Justin Brewer 的修复),1.0.0 沿用了它。相关改动还包括sdsrange整数溢出修复(#827、#830)。

4.3createArray长度参数改为size_t

redisReplyObjectFunctions.createArray的长度参数类型从int改为size_t(#597),任何自定义回复对象工厂的实现者都需要同步修改函数签名。

4.4 其他结构调整

  • redisContext新增privdata/free_privdata(用户自定义数据及析构函数,#855)与privctx(hiredis 内部管理 SSL 连接的指针)两个成员;
  • 1.0.0 同步更新了随附的sds库到上游最新版本,与 Redis 对齐(这会让链接旧版 hiredis 0.13 的应用不兼容);
  • 回复对象函数可通过redisReaderfn字段定制(如 hiredis-rb 用其创建 Ruby 对象),解析器默认最大嵌套深度为 7 的旧限制已在 1.0.0 移除(#794、#797)。

4.5 更早版本升级提示(0.13.x → 0.14.x → 1.0.0)

从 0.13.x 升级到 0.14.x 时,需要把redisReply.len的用途从int语义调整为size_t语义进行比较;0.14.0 还移除了redisReplyReaderCreateredisReplyReaderFreeredisReplyReaderFeedredisReplyReaderGetReplyredisReplyReaderSetPrivdataredisReplyReaderGetObjectredisReplyReaderGetError等旧别名(详见 ext/hiredis-1.0.2/CHANGELOG.md 中的替换表),并将 Makefile 的DEBUG变量更名为DEBUG_FLAGS,以避免与用户环境中其他软件的DEBUG变量冲突。

五、hiredis 在 ZeroTierOne 控制器中的实际落地

虽然 ZeroTierOne 核心网络栈本身不直接依赖 Redis,但它的中央控制器(Central Controller,位于 nonfree/controller/)在集群化部署中需要 Redis 支撑。控制器通过 redis-plus-plus(底层为 hiredis)访问 Redis,这一点可以从 nonfree/controller/CMakeLists.txt 中看到其对redis++::redis++_static静态目标的依赖,而 redis-plus-plus 又构建在 hiredis 之上。

具体使用形态包括:

  • 配置结构:nonfree/controller/Redis.hpp 定义了RedisConfig,包含hostnameportpasswordclusterMode四个字段,其中clusterMode用于区分单机 Redis 与 Redis Cluster;
  • 监听器:nonfree/controller/RedisListener.cpp 中的RedisNetworkListenerRedisMemberListener分别消费网络事件流与成员事件流:在集群模式下使用sw::redis::RedisCluster,非集群模式下使用sw::redis::Redis,通过xread阻塞读取指定 Stream key,处理成功后用xdel删除已消费条目,并统计Metrics::redis_net_notification/redis_mem_notification等指标;
  • 发布订阅与状态写回:控制器还借助 Redis 的发布订阅与 Stream 机制实现控制器变更通知与状态上报(见 nonfree/controller/PubSubListener.cpp、nonfree/controller/PubSubWriter.cpp 与 nonfree/controller/RedisStatusWriter.cpp 等)。

从源码结构看,ZeroTierOne 之所以在ext/下同时捆绑 hiredis 0.14.1 与 1.0.2,正是为了在不同 Linux 发行版与构建环境下提供可选的依赖来源——如 nonfree/controller/README_CENTRAL_CONTROLLER.md 所列的libhiredis-dev等系统包;当系统不提供该库时,ext/内的源码即可作为后备参与编译。

六、测试与构建配套

仓库内的 hiredis 1.0.2 源码树自带完整的测试与构建设施,方便读者在本地验证本文所述行为:

  • 测试程序:ext/hiredis-1.0.2/test.c 覆盖了同步 API、异步 API、RESP3 回复类型、PUSH 回调、SSL、分配器注入、超时、pipelining 等核心路径;ext/hiredis-1.0.2/test.sh 为测试执行脚本;
  • 示例程序:ext/hiredis-1.0.2/examples/ 提供example.c(同步基础)、example-ssl.c(SSL)、example-push.c(RESP3 PUSH)、example-libev.c/example-libevent.c/example-libuv.c/example-ae.c/example-glib.c/example-ivykis.c/example-macosx.c等各事件库适配器示例;
  • 事件适配器:ext/hiredis-1.0.2/adapters/ 内含 libev、libevent、libuv、ae(Redis 自带事件库)、glib、ivykis、macosx 的绑定头文件;
  • 构建系统:ext/hiredis-1.0.2/Makefile 与 ext/hiredis-1.0.2/CMakeLists.txt 双轨支持,并提供hiredis.pc.in/hiredis_ssl.pc.in的 pkg-config 模板与hiredis-config.cmake.in/hiredis_ssl-config.cmake.in的 CMake 包配置模板,便于第三方项目集成(如 ZeroTierOne 的 cmake/redis-plus-plus.cmake)。

七、升级建议与注意事项小结

  1. 安全优先:任何通过 SSL/TLS 连接 Redis 的 hiredis 用户都应升级到 1.0.2,以获取 CVE-2021-32765 修复;由于 1.0.2 与 1.0.0 功能完全相同,升级成本极低。
  2. 避开 1.0.1:1.0.1 错误提升了 SONAME,官方 changelog 明确要求改用 1.0.2。
  3. 超时语义变化:从 0.14.x 迁移时,options->timeout需改为options->connect_timeoutoptions->command_timeout,并确认两者语义是否符合预期(连接超时 vs 命令超时)。
  4. 长度类型变化:自定义回复对象工厂的createArray长度参数已是size_tredisReply.len自 0.14.0 起为size_t,比较时注意类型匹配。
  5. RESP3 的 PUSH 处理:默认自动拦截释放 PUSH 回复;只有在 MONITOR/SUBSCRIBE 式阻塞循环中才适合关闭自动处理。
  6. 版本兼容:仓库同时保留 hiredis 0.14.1 与 1.0.2 两个版本,实际编译哪个取决于平台与构建配置;ZeroTierOne 控制器依赖的 redis-plus-plus 底层即 hiredis,升级 hiredis 前应先确认对应 redis-plus-plus 版本的兼容性。

延伸阅读

  • 版本变更全文:ext/hiredis-1.0.2/CHANGELOG.md
  • 头文件与 API 声明:ext/hiredis-1.0.2/include/hiredis/hiredis.h、ext/hiredis-1.0.2/include/hiredis/async.h、ext/hiredis-1.0.2/include/hiredis/alloc.h
  • SSL 实现与示例:ext/hiredis-1.0.2/hiredis_ssl.h、ext/hiredis-1.0.2/ssl.c、ext/hiredis-1.0.2/examples/example-ssl.c
  • RESP3 PUSH 示例:ext/hiredis-1.0.2/examples/example-push.c
  • ZeroTierOne 控制器对 Redis 的使用:nonfree/controller/RedisListener.cpp、nonfree/controller/Redis.hpp、nonfree/controller/CMakeLists.txt

【免费下载链接】ZeroTierOneA Smart Ethernet Switch for Earth项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTierOne

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 4:27:40

ELK+Filebeat+Kafka日志分析平台在Rocky Linux 9.4上的搭建实践

先聊点实际的。做运维干了这么多年,我最怕听到的一句话就是“日志丢哪儿去了?”线上应用一抖动,开发、DBA、业务方全来找你。早期我也靠ssh到每台机器上敲tail -f,机器少点还能硬扛,等规模上来之后,几十台服…

作者头像 李华
网站建设 2026/9/14 4:23:54

数学建模也能Agent化:多智能体协作全流程实战

我去年年底开始认真琢磨一件事:数学建模这个场景,能不能被Agent化。先说背景。我本职做算法工程,业余会帮学生辅导数学建模竞赛,也接一些企业里的小型建模咨询。前几年大家普遍的做法,是把ChatGPT当高级搜索引擎用——…

作者头像 李华
网站建设 2026/9/14 4:23:40

4F相关器系统Matlab仿真:从透镜傅里叶变换到相关峰定位

简介:基于透镜傅立叶变换特性的4F相关器系统的Matlab仿真项目,聚焦光学信息处理与傅立叶光学中的频谱分析,适用于光电、通信、自动化等专业学生完成毕业设计、课程设计或大作业,也可作为相关科研人员的入门参考。压缩包共12个文件…

作者头像 李华
网站建设 2026/9/14 4:23:25

MongoDB Stable API:API 版本兼容性规则与 IDL 兼容性检查机制全解

MongoDB Stable API:API 版本兼容性规则与 IDL 兼容性检查机制全解 【免费下载链接】mongo The MongoDB Database 项目地址: https://gitcode.com/GitHub_Trending/mo/mongo 本文围绕 MongoDB 官方文档 STABLE_API_README.md 展开,讲清楚 Stable …

作者头像 李华