Suricata IP Reputation(IP 信誉)机制完全指南:配置、数据格式与 iprep 规则实战
网络安全【免费下载链接】suricataSuricata is a network Intrusion Detection System, Intrusion Prevention System and Network Security Monitoring engine developed by the OISF and the Suricata community.项目地址https://gitcode.com/gh_mirrors/su/suricata点击查看免费下载IP ReputationIP 信誉是 Suricata 引擎内用于对 IP 地址进行信誉评级的组件它负责收集、存储、更新并分发针对 IP 地址的信誉情报供检测规则与安全系统消费。本文基于 Suricata 官方用户手册中 doc/userguide/reputation/ipreputation/ip-reputation.rst 及其配套文档结合仓库内 src/reputation.c、src/reputation.h、src/detect-iprep.c 等源码实现完整讲解 IP 信誉的架构愿景、配置文件编写、两类数据文件格式、热重载机制以及通过iprep规则关键字编写信誉检测规则的方法。读完本文你将能独立为 Suricata 配置并维护一套可运行的 IP 信誉情报系统。一、IP Reputation 组件概述IP Reputation 组件的目的是在 Suricata 引擎内部对 IP 地址进行排名ranking。它会收集、存储、更新并分发关于 IP 地址的信誉情报reputation intelligence从而允许引擎把大量 IP 地址的正向或负向情报按多个类别category进行共享与分类。从文档描述的设计愿景看Suricata 采用Hub and Spoke中心辐射架构中心数据库The Hub负责收集、存储并汇总更新的 IP 信誉明细再把结果分发给用户侧的传感器数据库Spokes供用户安全系统使用。信誉数据的更新频率以及触发何种安全动作由用户的安全配置决定。该愿景落地需要三大部分工作引擎集成在 Suricata 引擎内部实现信誉数据的存储与匹配Hub 模块一个独立模块运行在独立系统上多数情况下是传感器们都能访问的中央数据库负责订阅一个或多个外部情报源feed做聚合再分发Hub 与传感器之间的通信协议负责双向同步信誉数据与反馈。Hub 的职责还包括允许本地管理员定义订阅的情报源、提供认证凭据并为每个情报源设置权重可以是整体权重也可以是按类别权重从而在某个情报源或类别不被信任时最小化其对整体信誉评分的影响。情报源可以配置为是否接受反馈feedback并在连接时上报该能力管理员可以覆盖此设置选择不提供反馈但传感器应在上线连接时向 Hub 上报该情况。Hub 聚合各情报源后为每个 IP 或 IP 网段IP Block生成一个平均单一评分再按配置分发给所有本地传感器它同时接收传感器的反馈并把反馈转发给其他传感器以及接受反馈的上游情报源。Hub 还应提供 API允许外部对数据库做统计分析并反馈回流例如本地站点可以据此批量调整某一地区全部 IP 网段的信誉。需要说明上述 Hub/Spoke 是官方文档描绘的架构愿景在当前仓库的源码中可以确认落地的是引擎集成部分信誉数据的加载、存储与规则匹配Hub 模块与通信协议属于独立的外部模块设计。二、配置文件三个核心指令IP Reputation 在 Suricata 的 YAML 配置文件中只有少量指令默认全部处于禁用状态。配置文件中典型的注释形态的写法如下# IP Reputation #reputation-categories-file: /etc/suricata/iprep/categories.txt #default-reputation-path: /etc/suricata/iprep #reputation-files: # - reputation.list下面逐一说明三个指令的语义与用法。reputation-categories-file分类文件路径。该文件负责把数字化的类别编号映射为短名称short name。reputation-categories-file: /etc/suricata/iprep/categories.txt从源码看分类编号被严格限制在SREP_MAX_CATS值为 60以内见 src/reputation.h。加载时SRepLoadCatFile 打开文件逐行调用 SRepCatSplitLine 解析出id,short name两段id 通过StringParseI32RangeCheck(..., 0, SREP_MAX_CATS - 1)校验后写入全局分类表srep_cat_table[60][32]short name 最长 31 字符。在 SRepInit 中可以看到只有当reputation-categories-file与reputation-files都未配置时IP Reputation 才会被判定为禁用源码注释为 IP reputation disabled若配置了reputation-files却没有配置分类文件则会报错退出。因此这两个指令通常要配套使用。default-reputation-pathreputation-files指令中列出的相对路径文件默认所在的目录。default-reputation-path: /etc/suricata/iprep源码函数 SRepCompleteFilePath 实现了路径拼接逻辑当文件名是相对路径时读取default-reputation-path配置项并前置拼接若文件名本身是绝对路径则直接使用不再拼接。在 Windows/Cygwin 环境下分隔符相应使用反斜杠。reputation-files一个 YAML 列表列出要加载的信誉数据文件。若文件名为绝对路径则直接加载否则以default-reputation-path为前缀拼出最终路径。reputation-files: - badhosts.list - knowngood.list - sharedhosting.list在 SRepInit 中引擎遍历该列表逐个调用 SRepLoadFile 读取文件加载失败时若failure_fatal为真配置要求严格模式将直接退出。每个文件的每一行调用 SRepSplitLine 解析出ip,category,score三段分类编号与分值分别用StringParseU8RangeCheck校验在SREP_MAX_CATS - 159与SREP_MAX_VAL127范围内。完整的启用示例将上述三个指令组合并取消注释即可启用 IP 信誉示例路径categories.txt与三个.list文件需预先按下一节格式准备好reputation-categories-file: /etc/suricata/iprep/categories.txt default-reputation-path: /etc/suricata/iprep reputation-files: - badhosts.list - knowngood.list - sharedhosting.list三、Hosts 表与资源调优IP 信誉信息存储在 Suricata 的host 表中因此 host 表的配置直接影响信誉功能的表现。这一点在 src/reputation.c 的加载逻辑中可以直接印证解析出 IP 后引擎调用HostGetHostFromHash(a)从 host 哈希表取或创建Host 对象再把信誉值写入h-iprep。如果 host 表容量不足HostGetHostFromHash会返回 NULL源码会打印failed to get a host, increase host.memcap并中止加载。因此当信誉数据覆盖的 IP 数量很大时可能需要提高 host 表的memcap与hash-size配置例如在配置文件中加大 host 段的相关参数host: memcap: 67108864 hash-size: 4096具体取值需结合部署内存与信誉 IP 数量调整。每个 Host 上挂载的SReputation结构在 src/reputation.h 中定义仅含两个字段uint32_t version信誉版本号和uint8_t rep[60]每个分类各占一个字节的分值数组。这意味着每个 Host 最多记录 60 个分类各自 0~127 的分值空间占用非常紧凑。四、热重载USR2 信号与版本化清理向 Suricata 进程发送USR2 信号会触发 IP 信誉数据重载并与常规的规则重载一起进行。重载期间 host 表会被更新以包含新数据由于 iprep 信息是带版本号的重载完成后 Suricata 会自动清理旧版本的 iprep 信息。源码中这套机制非常清晰SRepIncrVersion 在每次加载时递增srep_version并把新版本号记录到de_ctx-srep_version新写入的SReputation结构都会带上当前版本号SRepLoadFileFromFD 中若发现旧版本条目会先memset清零再写入实现替换旧数据重载完成后调用 SRepReloadComplete原子递增生效版本srep_eversionhost 超时回收逻辑调用 SRepHostTimedOut若某个 Host 上 iprep 的版本号小于当前生效版本说明是旧数据随即释放h-iprep并回收引用计数。注意两个重载边界重载只重新加载reputation-files指定的信誉文件分类文件不会被重载如果分类categories发生变化需要重启 Suricata才能生效。这也与源码一致SRepInit的注释明确写道If this function is called more than once, the category file is not reloaded且 SRepInitComplete 只在首次初始化时把生效版本置 1。五、数据文件格式IP 信誉涉及两类数据文件其完整格式规范见 doc/userguide/reputation/ipreputation/ip-reputation-format.rst。5.1 分类文件Categories File分类文件提供分类编号 → 短名称 → 长描述的映射是简单的 CSV 格式id,short name,description示例1,BadHosts,Known bad hosts 2,Google,Known google host分类编号 id 的最大值目前硬编码为60对应源码中的SREP_MAX_CATS 60。规则关键字里引用的分类短名称如BadHosts就来自该文件解析规则时引擎通过 SCSRepCatGetByShortname 在分类表中线性查找短名称对应的编号。文件中的注释行以#开头与空行会被 GetEffectiveLineLen 跳过。5.2 信誉文件Reputation File信誉文件列出各主机在分类中的信誉分值同样是简单的 CSV 格式ip,category,reputation scoreipIPv4 点分十进制地址或 IPv6 地址两种地址均支持 CIDR 网段表示法category分类编号即分类文件中定义的数字reputation score该 IP 属于该分类的置信度取值1 到 1270 表示无数据。示例1.2.3.4,1,101 1.1.1.0/24,6,88如果同一个 IP 在多个分类中都有分值则应在文件中多次列出1.1.1.1,1,10 1.1.1.1,2,10上面两行表示1.1.1.1同时属于分类 1 和分类 2各自分值为 10。源码对两种形态的处理路径不同值得展开说明CIDR 网段行含/字符走 SRepCIDRAddNetblock 分支根据是否含:判定 IPv4/IPv6分别插入按分类组织的 radix 树srep_ipv4_tree[cat]/srep_ipv6_tree[cat]每个分类一棵树共 60 棵见 src/reputation.h。查询时调用 SRepCIDRGetIPv4IPRep / SRepCIDRGetIPv6IPRep 的SCRadix*TreeFindBestMatch即最长前缀匹配因此1.1.1.0/24的网段条目可覆盖该网段内任意具体 IP 的查询单 IP 行走 host 表分支解析 IP 后从 host 哈希表取得 Host 对象并写入h-iprep。日常匹配时规则引擎优先查 Host 上缓存的iprep数据见下文 iprep 关键字src/detect-iprep.c 中的GetRep只接受版本号不小于当前检测引擎版本的信誉数据以此保证重载过程中新旧数据不会错乱。六、在规则中使用 iprep 关键字IP 信誉可以在规则中通过iprep关键字使用完整说明见 doc/userguide/rules/ip-reputation-rules.rst。关键字在源码 src/detect-iprep.c 中注册描述为 match on the IP reputation information for a host。6.1 基本语法iprep:side to check,category,operator,reputation score参数说明参数取值/含义side to checkany、src、dst、both检查源、目的或任意一侧category分类短名称来自 categories 文件operator、、、、reputation score0–127示例规则内网主机访问 CnC 分类中信誉分大于 30 的地址时报警。alert ip $HOME_NET any - any any (msg:IPREP internal host talking to CnC server; flow:to_server; iprep:dst,CnC,,30; sid:1; rev:1;)该规则在$HOME_NET中的主机作为客户端与CnC分类中信誉分值大于 30 的任意 IP 通信时触发告警。6.2 isset 与 isnotset集合成员测试isset与isnotset用于测试信誉集合成员资格iprep:side to check,category,isset|isnotsetside to checkany、src、dst、bothcategory分类短名称。isset等价于一个,0的判断只要该 IP 在指定分类中存在任意分值即属于该集合即视为匹配。示例阻断来自known-bad-hosts分类集合的流量。drop ip $HOME_NET any - any any (iprep:src,known-bad-hosts,isset; sid:1;)示例阻断所有不具备trusted-hosts信任分值的流量isnotset测试 IP 是否不属于该集合。drop ip $HOME_NET any - any any (iprep:src,trusted-hosts,isnotset; sid:1;)6.3 与 IP-only 规则的兼容性iprep关键字兼容IP-only 规则仅由 IP 层字段组成的规则。这意味着下面这类规则每个流方向只会被检查一次alert ip any any - any any (msg:IPREP High Value CnC; iprep:src,CnC,,100; sid:1; rev:1;)源码层面DetectIPRepRegister 为iprep关键字设置了SIGMATCH_IPONLY_COMPAT | SIGMATCH_SUPPORT_FIREWALL标志位正是该兼容性的直接实现依据同时匹配函数还会借助包的PKT_HOST_SRC_LOOKED_UP/PKT_HOST_DST_LOOKED_UP标志与host_src/host_dst缓存src/detect-iprep.c避免对同一地址重复查 host 表。此外SIGMATCH_SUPPORT_FIREWALL标志也表明该关键字可用于 IPS 模式的丢弃drop动作。七、源码级实现与测试佐证综合来看IP Reputation 的运行时实现包含三条关键链路加载链路SRepInit读取配置 → 加载分类文件 → 递增版本 → 遍历加载信誉文件→SRepLoadFileFromFD逐行解析单 IP 写入 host 表 / CIDR 写入 radix 树→SRepInitComplete置生效版本为 1。对应源码 src/reputation.c匹配链路规则解析时SCSRepCatGetByShortname把短名称转编号运行时DetectIPRepMatch通过GetHostRepSrc/GetHostRepDst读取 Host 上的iprep数组再与规则中的操作符和分值比较。对应源码 src/detect-iprep.c重载与回收链路USR2 触发重载 →SRepReloadComplete递增生效版本 → host 超时回收时SRepHostTimedOut依据版本号清理过期 iprep 数据。对应源码 src/reputation.c。仓库内的单元测试 src/tests/reputation.c 直接验证了文件解析与匹配行为例如SRepTest01用1.2.3.4,1,2断言能正确解析出 IP、分类 1 与分值 2TEST_INIT_WITH_PACKET等宏则构造真实 TCP 报文用于端到端验证信誉匹配。这些测试证明了ip,category,score格式与 CIDR 处理的正确性也可以作为读者快速验证自己信誉文件格式的参考例如对照格式要求自查 CSV 列数、编号与分值范围。八、快速上手清单准备分类文件categories.txt每行id,short name,descriptionid 范围 0–59准备信誉文件如badhosts.list每行ip,category,score支持 IPv4/IPv6 与 CIDR分值 1–127多分类需重复列出在 Suricata YAML 中取消注释并配置reputation-categories-file、default-reputation-path、reputation-files三个指令见第二节完整示例必要时同步调大host.memcap/hash-size启动或重启 Suricata 使首次配置生效之后修改信誉文件后发送kill -USR2 pid触发重载分类文件变更仍需重启编写iprep规则基本比较或isset/isnotset配合alert/drop动作实现告警与 IPS 阻断。至此从配置、数据格式到规则匹配再到源码级版本管理与热重载机制一套完整的 Suricata IP Reputation 使用链路已经打通。进一步深入可继续阅读仓库中的 ip-reputation-config.rst配置细节、ip-reputation-format.rst格式细节与 ip-reputation-rules.rst规则细节以及 src/reputation.c 与 src/detect-iprep.c 的完整实现。赞分享网络安全【免费下载链接】suricataSuricata is a network Intrusion Detection System, Intrusion Prevention System and Network Security Monitoring engine developed by the OISF and the Suricata community.项目地址https://gitcode.com/gh_mirrors/su/suricata点击查看免费下载相关推荐Suricata IP Reputation 配置完全指南从 reputation-files 到规则联动Suricata IP Reputation 配置完全指南从 reputation files 到规则联动 Suricata 的 IP Reputation网络安全Suricata IP Reputation 文件格式详解categories 与 reputation 数据文件实战指南Suricata IP Reputation 文件格式详解categories 与 reputation 数据文件实战指南 Suricata 的 IP Rep网络安全Label Studio SaaS 环境配置与使用限制完全指南IP、主机名、速率限制与 Webhook 规则Label Studio SaaS 环境配置与使用限制完全指南IP、主机名、速率限制与 Webhook 规则 Label Studio 官方提供托管式 Saa数据标注人工智能上一篇如何解决mini-css-extract-plugin常见错误与警告终极指南下一篇Complete-System-Design负载均衡技术消息队列与并发处理最佳实践 创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

(新手适用)OpenClaw 2.6.6 Windows 部署教程|拦截与报错一站式解决:把 settings 改到 TaoToken

(新手适用)OpenClaw 2.6.6 Windows 部署教程|拦截与报错一站式解决:把 settings 改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 1:51:14 阅读更多 →
Stagewise 中的 Remotion 静态资源管理:public/ 目录、staticFile() 与媒体组件导入实战

Stagewise 中的 Remotion 静态资源管理:public/ 目录、staticFile() 与媒体组件导入实战

人工智能AI Agent代码智能体开发工具 【免费下载链接】stagewise The Open Source Agentic IDE. Create and orchestrate coding agents, show app previews and run git workflows. Use your favorite models across all providers. 项目地址: https://gitcode.com…

2026/10/9 1:51:14 阅读更多 →
MASTG iOS 设备 Shell 完全指南:SSH、USB 隧道、逆向 Shell 与模拟器 Shell 实战

MASTG iOS 设备 Shell 完全指南:SSH、USB 隧道、逆向 Shell 与模拟器 Shell 实战

文档教程网络安全 【免费下载链接】mastg The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security W…

2026/10/9 1:51:14 阅读更多 →

最新新闻

JavaWeb在线问卷调查系统课程设计:结构部署与核心代码解析

JavaWeb在线问卷调查系统课程设计:结构部署与核心代码解析

简介:基于JavaWeb的在线问卷调查系统课程设计源码包,面向需要完成Java课设、毕设或学习Servlet/JSP与Spring Boot整合开发的学生和开发者。系统覆盖用户注册登录、问卷创建与填写、管理员统一管理、多题型支持(单选、多选、文本题&#xff09…

2026/10/9 4:00:29 阅读更多 →
JavaWeb在线问卷调查系统:从建表到统计的完整实践

JavaWeb在线问卷调查系统:从建表到统计的完整实践

简介:这是一份基于JavaWeb的在线问卷调查系统课程设计源码包,涵盖前后端完整工程与数据库脚本,面向需要完成Java课设或学习Spring Boot、ServletJSP项目的开发者。系统实现用户注册登录、问卷创建与填写、单选题多选题文本题、发布暂停结束、…

2026/10/9 4:00:29 阅读更多 →
PyYAML实战指南:从配置文件解析到安全加载与避坑

PyYAML实战指南:从配置文件解析到安全加载与避坑

作为一个天天跟配置文件打交道的 Python 开发者,我可以直接告诉你:PyYAML 是那种你用一次就再也离不开的库。项目里无论是 CI/CD 流水线参数、爬虫的抓取规则、深度学习模型的超参数,还是后端服务的路由配置,用 YAML 写出来就是比…

2026/10/9 4:00:29 阅读更多 →
基于微信小程序的心理健康咨询系统设计与实现

基于微信小程序的心理健康咨询系统设计与实现

搞过计算机毕业设计的人都知道,选题是整个环节里最要命的一步。选个图书管理系统、学生选课系统这类,答辩老师看一眼就翻页,因为千篇一律到没有记忆点;选个算法题,工作量又很难撑起一篇合格的毕业论文,代码…

2026/10/9 4:00:29 阅读更多 →
全球开源发展愿景论坛:从议程拆解到参会议题指南

全球开源发展愿景论坛:从议程拆解到参会议题指南

看到这届“全球开源发展愿景论坛”的议程表正式发布,我第一反应是:这个论坛是真的想把“开源无界,共筑未来”从口号变成可讨论、可落地的议题集合。前几年大家聊开源,更多还是盯着代码仓库、许可证、社区PR,但今年这份…

2026/10/9 4:00:29 阅读更多 →
基于EasyHook的.NET虚拟文件系统:从API Hook到路径重定向实战

基于EasyHook的.NET虚拟文件系统:从API Hook到路径重定向实战

简介:这是一份基于 .NET 与 EasyHook 的虚拟文件系统完整源码,面向熟悉 C#、希望深入理解 Windows 文件操作 Hook 机制的开发者。项目通过拦截 FindFirstFileW、FindNextFileW、CreateFileW 等关键 API,实现文件查找、创建等行为的监控与自定…

2026/10/9 3:59:28 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 13:34:55 阅读更多 →