OpenGFW for iKuai
=================

基于 Netfilter NFQUEUE 的深度报文检测（DPI）插件。

引擎（OpenGFW）已内嵌进本插件，安装包内只有一个可执行文件 opengfwd：
检测引擎、面板、内核规则管理、自我保护都在同一个进程里。没有子进程，
没有日志管道。

面板地址
--------
http://<lan1-ip>:9170/dashboard

首次登录用默认账号 admin / ikuai8.com（HTTP Basic）。面板能开关流量拦截，
请改掉密码；也可以把用户名改成 off 完全关闭鉴权（不建议）。面板只绑定 LAN1
地址，不会暴露到外网。

拦截默认关闭
------------
安装后不会阻断任何流量。默认规则是「只记录不拦截」，用来先观察识别结果，
确认符合预期后再把 action 改成 block。

两种模式
--------
网关模式（推荐）
  处理转发流量（FORWARD 链），即 LAN 客户端的上网流量。
  路由器自身的管理面不受影响。

本机模式（高级，慎用）
  处理路由器自身流量（INPUT/OUTPUT 链）。
  注意：此模式会接管管理面。它把路由器自己的出入流量交到用户态，一旦插件
  停止消费，队列里的报文会被扣住，管理通道可能随之卡住。插件内置两重保护
  （下文的「过载保护」与自动卸载），但都只是减小影响、不能消除影响。
  本机模式不支持「全量接管」：那会把设备自身全部流量送进插件，实测（1 条规则
  即可）会让自身出网停摆。该组合会被拒绝；旧版本若已保存，启动时会自动改为
  辅助增强并在日志说明。
  仅在需要短时诊断时使用，用完请立即关闭。
  自我保护：开启本机模式后会周期性探测本机出网，连续失败则自动卸下内核规则
  并关闭拦截（无需人工介入即可恢复）。本机模式不跨重启保留。

识别范围
--------
本插件不是要取代爱快内置的应用识别，而是补它的盲区。识别范围决定两者的分工：

辅助增强（默认）
  只处理内核未能识别的流量（appid 为 0 且内核未裁决）。
  判定条件是「内核未识别（appid 为 0）且内核未裁决」。
  爱快内置的应用识别、限速、MAC 绑定上网控制、ping 等功能都不受影响。

  ★ 重要（真机实测）：按域名/DNS 的拦截（例如 gfwlist 这类规则）在辅助增强下【不生效】——
  爱快内核已识别的流不会进入本插件。实测同一份 gfwlist 规则集：
  辅助增强下 80/80 条 DNS 查询全部放行（引擎根本看不到这些流）；
  切到全量接管后 80/80 条被拦、对照域名 0/40 误拦。
  要用域名类规则，请选「全量接管」（且只支持网关模式）。

全量接管（备选，仅网关模式）
  所有转发流量都经过本插件，规...[truncated]
  代价是性能与延迟：每个报文都要送到用户态处理，大流量下 CPU 与延迟会上升；
  同时规则写错的波及面从「内核未识别的那部分」扩大到全部转发流量。
  仅在明确需要时才选，应用设置里可切换。

组播噪声过滤
------------
默认开启。把组播与广播报文排除在检测队列之外：这类报文内核从不参与分类，会持续
占用队列（仅 SSDP/DLNA 的广播就足够占住），排除后不会漏掉任何需要检测的流量。
IPv4 与 IPv6 分别探测（两个协议族的匹配写法不同），若某个协议族不支持，面板会
明确显示为「部分生效」，而不是假装已生效。

过载保护
--------
使用爱快内核自带的 NFQUEUE 过载保护（默认开启）。

不开时用的是内核原生行为：队列一旦打满，后续报文直接被丢弃——在内网里这会
表现为断网。开启后，队列占用超过 90% 时改为放行，报文不再被丢。

请注意这是减小影响，不是免疫：已经进入队列的报文仍然在等待，所以插件若停止
处理，最多仍会有「队列长度」这么多报文被扣住。真正兜底的是插件自身的设计
（读取永不阻塞、异常自动卸载）与这个内核开关一起作用。

该开关是全内核生效的，与其它使用 NFQUEUE 的组件共用；本插件启动拦截时会按
设置置位，停止时还原为原先的值。

处理能力（真机实测，供选型参考）
--------
「全量接管」是把转发报文逐个送进用户态判定，成本按【报文】计，不是按流。实测
（4 核 x86，DNS 类小报文，4310 条域名规则）：

  约 10 万包/秒的极端小包压力下：约 4.5 万包/秒可全额处理且队列不积压（约 1.4 核）；
  压力继续升高时队列开始积压，但内核过载保护会让报文放行而不是丢弃——
  此时表现是「过滤效果下降」，不是「网络中断」。

真实网关流量远低于此：1500 字节满包时 4.5 万包/秒相当于约 540 Mbps，而内网
浏览/视频的包速率通常只有几千到几万包/秒。若你只需要按域名拦截 DNS，建议把
「流量筛选」设为「仅 DNS」—— 那时代价几乎为零，实测与不装插件处于同一量级。

流量筛选（降低开销的主要办法）
--------
决定哪些报文进入本插件：

  全部流量   每个转发报文都送进用户态，代价最高（见上）。
  仅 DNS     只送 53 端口（TCP 与 UDP）。按域名拦截（gfwlist 那种）够用，
             代价几乎为零 —— 这是「只想拦域名」时的推荐值。
  仅网页     只送 80 与 443。按 TLS SNI / HTTP 拦截需要它。
  自定义     自填端口，支持范围（如 8000-8100），TCP 与 UDP 都生效。

注意两件事：

  1. 没被包含的流量【完全不会】被本插件检测。比如把筛选设为「仅 DNS」，任何
     按 TLS SNI 拦截的规则都不会生效 —— 那是流量根本没被看到，不是规则写错。
  2. 筛选与「识别范围」是两个独立维度：前者决定「看多少」，后者决定「对谁负责」
     （辅助增强只管内核未识别的流，全量接管接管全部转发流量）。

日志
--------
等级越低日志越详细、开销越大。引擎对每个报文的判定记录会格式化整份 DNS 属性，
所以等级设为 info/debug 且流量较大时会明显拖慢转发（实测未做限制时吞吐被压到
约 9 千包/秒）。现在有每秒 500 条的上限，超出部分丢弃并计数，面板会提示
「已丢弃 N 条」；排查完建议调回 warn 或 error。

部署前提
--------
以下情况插件根本看不到流量，会直接拒绝启用并说明原因（而不是安静地一条都不
命中，让人误以为"没有匹配流量"）：

- 链路模式为旁路模式或 SD-WAN 网桥：这类流量走二层桥接，不经过 iptables。
- 检测到网桥透传。

加速模式（FASTOFFLOAD）不阻止启用，但会提示：开启后每条流只能看到前若干报文，
依赖整条流行为的检测（如全加密流量判定）会失效。

规则写法
--------
规则为 YAML 列表，每条形如：

  - name: log-dns
    action: allow      # allow / block / drop
    log: true
    expr: dns != nil

常用表达式片段（字段名必须是真实存在的分析器）：

  dns != nil                              DNS 查询
  tls != nil && tls.req.sni != ""         TLS SNI（注意 SNI 在 tls.req 下）
  quic != nil                             QUIC / HTTP3
  http != nil                             HTTP
  ssh != nil / socks != nil               SSH / SOCKS
  wireguard != nil / openvpn != nil       WireGuard / OpenVPN
  fet != nil && fet.yes                   全加密流量（Shadowsocks 类）
  trojan != nil                           Trojan 特征

注意：引擎不会拒绝写错的字段名（规则会静默永不命中），面板会在保存时校验，
请以面板的校验结果为准。例如并不存在 ss / vmess 分析器，全加密流量检测是 fet。

绕过名单
--------
填写不进入检测队列的 IP 或 CIDR，多个用逗号或换行分隔。规则会插在 NFQUEUE
之前，这些地址直接放行，不消耗检测资源。

安全须知
--------
- 开启拦截前，请先用「只记录」规则观察日志。
- 关闭拦截时会自动卸下内核挂载，不留残余规则；异常退出后重新启动也会清理。
- 若上次未正常退出（拦截仍处于挂载状态），本次开机不会自动恢复拦截。
- 本机模式不跨重启保留，每次都需要手动开启。
- 应用设置里的改动（识别范围、过载保护）在下次启动插件时生效；面板里的改动
  立即生效。

与爱快内置功能的关系
--------------------
在网络流量的处理顺序上，本插件的钩子位于爱快自身功能链之后：

  转发路径：ACL_MAC（MAC 绑定）→ 连接数限制 → 限速 → 防火墙 → 本插件

所以辅助增强模式不会绕过或削弱这些功能。全量接管的代价见上文。

日志
----
面板「日志」页显示引擎识别结果（命中规则、解析到的协议字段）。
文件：<插件目录>/log/engine.log（引擎输出）、log/run.log（插件自身状态）。
