feat: 发布 0.6.22,接入向导与文档补上 IPv6 嗅探和 FastTrack 命令;自检检查 IPv6 FastTrack

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Su YijunandClaude Opus 5.5 committed 2026-10-25 17:37:33 +08:00
1 parent b0fcb7d20e
commit 2de45dabc7
10 files changed
+72 -7

No files matched your search

+8
View File
@@ -1,5 +1,13 @@
# Changelog
## [0.6.22] - 2026-10-25
接入向导、文档补上 IPv6 嗅探与 FastTrack;自检检查 IPv6 的 FastTrack
- **接入向导**(系统设置 → 接入与自检)新增 3b、3c 两步:路由器开了 IPv6 时在 `/ipv6 firewall mangle` 再加一份 DNS / SNI 嗅探(4 条);开了 FastTrack 时让 IPv4 / IPv6 每条连接的前 10KB 不走 FastTrack。此前向导只有 IPv4 命令,IPv6 流量的 DNS 应答和握手全都镜像不到。
- **接入自检**读取 `/ipv6/firewall/filter`:IPv6 的 FastTrack 规则(ROS 7.18 起支持)没有限定 connection-bytes 时提示,并给出修改命令。
- README 与 `docs/RouterOS配置.md` 补充 IPv6 一节:为什么必须做、4 条命令、镜像目标可以用 ROS-DPI 的 IPv4 地址、流量采集不用另配。
## [0.6.21] - 2026-10-25
社区共享库重做:项目自带社区主站,不再依赖 WebDAV / 第三方存储(debug13~22 复查)
+1
View File
@@ -36,6 +36,7 @@ services:
## What's new
- **0.6.22**: 接入向导与文档补上 IPv6 嗅探(`/ipv6 firewall mangle` 4 条)和 FastTrack(IPv4 / IPv6)命令;自检检查 IPv6 的 FastTrack。Setup guide and docs now include IPv6 sniff rules and FastTrack commands for both families; the self-check also flags IPv6 FastTrack without a connection-bytes limit.
- **0.6.21**: 社区共享库重做——项目自带社区主站,不再需要 WebDAV / 第三方存储:令牌注册、按来源网络计票(≥2 个不同网络一致才发布,防伪造实例刷票)、ETag 增量拉取、本地缓存;修复 0.6.20 部署量接口 500、共享任务从未运行、开关保存不上。接入自检新增 IPv6 嗅探规则检查,FastTrack 已限定 connection-bytes 时不再误报,并直接给出修改命令。Community library rebuilt around a built-in hub (no WebDAV/third-party storage): per-instance tokens, votes counted per source network, ETag pulls, local cache; fixes the 0.6.20 deployments 500 and the never-running share job. Self-check now flags missing IPv6 sniff rules.
- **0.6.12 / 0.6.11 / 0.6.10 / 0.6.9 / 0.6.8**: 自学习与共享系列。**本地自学习库**:本网络实测的「IP → 应用」(IPv6 按 /64 前缀聚合)与「域名 → 应用」长期记忆,每小时重建,DNS 缓存过期、DoH、裸 IP 流量都能按记忆归类;**社区共享库**:各部署实例把实测结论匿名共享(中转聚合、至少 2 个实例见过才发布),本地实测优先、社区只补空白;**全球部署量**:实例心跳上报,中转公开已部署 / 在线 / 离线数量;共享总开关默认打开;**一键自更新**:Linux 二进制部署在网页上检测并一键升级(自动下载、替换、重启服务);**Linux 单文件二进制部署**:`install.sh` 一键安装 systemd 服务(SQLite 零配置起步);修复落库卡死(代理长域名撑爆 access_log.remote 列导致每分钟落库失败、在线终端归零);组播 / 广播流量不再计入统计;17 个 DPI 大类配色互异。
- **0.6.7**: fixes for the 0.6.5 / 0.6.6 history reclassification and rule auto-registration. Reclassification now only touches days before today and only upgrades vague rows (HTTPS / Chinese websites / unknown / CDN) to a specific app — it no longer downgrades apps identified live by IP range, port or ASN. New upstream blackmatrix7 directories are downloaded first and then assigned by a vote of the existing libraries. The manual dark theme now uses the 17 distinct group colors, and the AdGuard Home password is masked in the operation log.
+10
View File
@@ -165,6 +165,16 @@ EOF
/ip firewall mangle add chain=forward protocol=tcp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-SNI
/ip firewall mangle add chain=forward protocol=udp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-SNI
# 3b. 路由器开了 IPv6 时必须再加一份(国内宽带默认有 IPv6,大流量应用优先走 IPv6)
/ipv6 firewall mangle add chain=output protocol=udp src-port=53 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-DNS
/ipv6 firewall mangle add chain=forward protocol=udp src-port=53 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-DNS
/ipv6 firewall mangle add chain=forward protocol=tcp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-SNI
/ipv6 firewall mangle add chain=forward protocol=udp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-SNI
# 3c. 开了 FastTrack 时:每条连接的前 10KB 不走 FastTrack,握手才镜像得到
/ip firewall filter set [find action=fasttrack-connection] connection-bytes=10000-0
/ipv6 firewall filter set [find action=fasttrack-connection] connection-bytes=10000-0
# 4. 只读 API 账号(可选:主机名、WAN 速率)
/user group add name=rosdpi policy=read,rest-api,api,!write,!policy,!sensitive
/user add name=rosdpi group=rosdpi password=<强密码> address=192.168.88.10
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.6.21"
__version__ = "0.6.22"
+7 -1
View File
@@ -43,6 +43,7 @@ class RosPoller:
self.mangle: list[dict] = [] # 接入自检用:RouterOS 的 mangle 规则(只读)
self.ip_settings: dict = {}
self.filter_rules: list[dict] | None = None # /ip/firewall/filter(看 FastTrack 规则有没有限定 connection-bytes)
self.filter6_rules: list[dict] = [] # /ipv6/firewall/filter(ROS 7.18 起 IPv6 也能 FastTrack)
self.has_ipv6 = False # 路由器上有没有 IPv6 公网地址
self._sample_prev: dict[str, tuple[float, int, int]] = {}
@@ -98,13 +99,14 @@ class RosPoller:
("pools", "/ip/pool"), ("servers", "/ip/dhcp-server"), ("dhcpc", "/ip/dhcp-client"),
("pppoe", "/interface/pppoe-client"), ("mangle", "/ip/firewall/mangle"),
("mangle6", "/ipv6/firewall/mangle"), ("ipset", "/ip/settings"),
("filter", "/ip/firewall/filter"))}
("filter", "/ip/firewall/filter"), ("filter6", "/ipv6/firewall/filter"))}
self._apply(ifaces, arp, leases, addrs, routes, nb6, addrs6)
self._apply_status(ifaces, addrs, leases, routes, extra)
self.mangle = [{**r, "_family": "ipv4"} for r in extra["mangle"] or []] + \
[{**r, "_family": "ipv6"} for r in extra["mangle6"] or []]
self.ip_settings = extra["ipset"] if isinstance(extra["ipset"], dict) else {}
self.filter_rules = extra["filter"] if isinstance(extra["filter"], list) else None
self.filter6_rules = extra["filter6"] if isinstance(extra["filter6"], list) else []
self.has_ipv6 = any(_global_v6(a.get("address")) and a.get("disabled") != "true"
for a in addrs6 or [])
# 全部成功后再更新展示用的状态,失败时保留上一次的结果
@@ -307,6 +309,10 @@ class RosPoller:
ft_limited = bool(ft_rules) and all(r.get("connection-bytes") for r in ft_rules)
if fasttrack and not ft_limited:
issues.append("fasttrack")
# IPv6 的 FastTrack 没有 ipv4-fasttrack-active 这样的状态位,直接看规则:启用了且没限定 connection-bytes 就提示
if any(r.get("action") == "fasttrack-connection" and r.get("disabled") != "true" and not r.get("connection-bytes")
for r in self.filter6_rules):
issues.append("fasttrack6")
return {"checked": True, "port": port, "target": ref[0] if ref else None, "rules": rules, "issues": issues,
"fasttrack": fasttrack, "fasttrack_limited": fasttrack and ft_limited}
+8
View File
@@ -112,6 +112,14 @@ def test_fasttrack_check_respects_connection_bytes(monkeypatch):
poller.poll()
chk = poller.check()
assert "fasttrack" not in chk["issues"] and chk["fasttrack_limited"]
# IPv6 的 FastTrack 规则同样要限定 connection-bytes
rule6 = {".id": "*3", "action": "fasttrack-connection", "chain": "forward", "disabled": "false"}
monkeypatch.setitem(ROS, "/rest/ipv6/firewall/filter", [rule6])
poller.poll()
assert "fasttrack6" in poller.check()["issues"]
monkeypatch.setitem(ROS, "/rest/ipv6/firewall/filter", [{**rule6, "connection-bytes": "10000-0"}])
poller.poll()
assert "fasttrack6" not in poller.check()["issues"]
# 读不到 filter 表(只读账号没权限):按旧办法提示
monkeypatch.delitem(ROS, "/rest/ip/firewall/filter")
poller.poll()
+21 -1
View File
@@ -73,7 +73,27 @@
这样每条连接的前 10KB 走正常路径(会被嗅探),之后照常 FastTrack。
**IPv6**:IPv6 流量需要在 `/ipv6 firewall mangle` 下再加一份相同的规则(DNS 嗅探的两条也一样)。
IPv6 也开了 FastTrack(ROS 7.18 起支持)时同样处理:
```routeros
/ipv6 firewall filter set [find action=fasttrack-connection] connection-bytes=10000-0
```
### IPv6(路由器开了 IPv6 时必须做)
国内宽带默认下发 IPv6,抖音、B 站、淘宝等大流量应用会优先走 IPv6。IPv6 的 DNS 应答和 HTTPS / QUIC 握手只经过 `/ipv6 firewall mangle`,只配 IPv4 规则时这部分流量只能按 IP 归类(大多落进「国内网络」)。在 IPv6 下再加一份同样的 4 条规则:
```routeros
/ipv6 firewall mangle add chain=output protocol=udp src-port=53 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-DNS
/ipv6 firewall mangle add chain=forward protocol=udp src-port=53 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-DNS
/ipv6 firewall mangle add chain=forward protocol=tcp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-SNI
/ipv6 firewall mangle add chain=forward protocol=udp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=192.168.88.10 sniff-target-port=37008 comment=ROSDPI-SNI
```
- 镜像包可以照样发到 ROS-DPI 的 **IPv4 地址**,ROS-DPI 不需要 IPv6 地址;ROS 提示 `sniff-target` 无效时改填 ROS-DPI 的 IPv6 地址(接收端口同时监听 IPv4 / IPv6)。
- 流量采集不用另配:`/ip traffic-flow` 同时导出 IPv4 和 IPv6 的流。
- LAN 的 IPv6 前缀:配了只读 API 会自动加入;没配时在 系统设置 → 网络 手动填写。
- **系统设置 → 接入自检** 会检查:路由器有 IPv6 公网地址却没有 IPv6 嗅探规则、IPv4 / IPv6 的 FastTrack 没有限定 connection-bytes,都会提示并给出要执行的命令。
## 4. 只读 API 账号(可选)
+1
View File
@@ -178,6 +178,7 @@ export default {
no_dns: 'No working DNS sniffing rule.', no_sni: 'No working SNI rule: HTTPS / QUIC handshakes never reach ROS-DPI.',
no_quic: 'Only a TCP SNI rule; UDP 443 (QUIC / HTTP3) is missing, so QUIC-heavy apps such as Douyin and YouTube are not identified.',
fasttrack: 'FastTrack is on and its rule has no connection-bytes limit: fast-tracked connections skip mangle, so handshakes are not mirrored and much HTTPS falls back to IP-only buckets. The command below keeps the first 10 KB of each connection off FastTrack; CPU cost barely changes.',
fasttrack6: 'IPv6 FastTrack is on (/ipv6 firewall filter) without a connection-bytes limit: handshakes of IPv6 connections are not mirrored. The command below keeps the first 10 KB of each connection off FastTrack as well.',
no_ipv6: 'The router has public IPv6 addresses but sniff rules exist for IPv4 only: DNS answers and HTTPS / QUIC handshakes over IPv6 are invisible. The commands below add the same rules under /ipv6 firewall mangle; if sniff-target is rejected, use the IPv6 address of ROS-DPI.',
},
},
+1
View File
@@ -178,6 +178,7 @@ export default {
no_dns: '没有生效的 DNS 嗅探规则。', no_sni: '没有生效的 SNI 规则:HTTPS / QUIC 握手到不了 ROS-DPI。',
no_quic: '只有 TCP 的 SNI 规则,缺少 UDP 443(QUIC / HTTP3),抖音、YouTube 等大量走 QUIC 的流量认不出来。',
fasttrack: 'FastTrack 已启用,且规则没有限定 connection-bytes:被 FastTrack 的连接不经过 mangle,握手包镜像不到,大量 HTTPS 只能按 IP 归到「国内网络」。下方命令让每条连接的前 10KB 不走 FastTrack,CPU 占用几乎不变。',
fasttrack6: 'IPv6 也开了 FastTrack(/ipv6 firewall filter),且没有限定 connection-bytes:IPv6 连接的握手镜像不到。下方命令同样让每条连接的前 10KB 不走 FastTrack。',
no_ipv6: '路由器有 IPv6 公网地址,但嗅探规则只有 IPv4 的:走 IPv6 的 DNS 应答和 HTTPS / QUIC 握手都看不到(国内运营商默认下发 IPv6,这部分流量通常很大)。下方命令在 /ipv6 firewall mangle 补一份;若提示 sniff-target 无效,改填 ROS-DPI 的 IPv6 地址。',
},
},
+14 -4
View File
@@ -434,6 +434,17 @@ const guide = computed(() => {
/ip firewall mangle add chain=forward protocol=tcp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=${ip} sniff-target-port=${p.tzsp} comment=ROSDPI-SNI
/ip firewall mangle add chain=forward protocol=udp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=${ip} sniff-target-port=${p.tzsp} comment=ROSDPI-SNI
# 3b. 路由器开了 IPv6 时(国内宽带默认都有):IPv6 的 DNS 应答和握手只经过 /ipv6 firewall mangle,再加一份
# 镜像包照样发到 ROS-DPI 的 IPv4 地址;ROS 提示 sniff-target 无效时改填 ROS-DPI 的 IPv6 地址
/ipv6 firewall mangle add chain=output protocol=udp src-port=53 action=sniff-tzsp sniff-target=${ip} sniff-target-port=${p.tzsp} comment=ROSDPI-DNS
/ipv6 firewall mangle add chain=forward protocol=udp src-port=53 action=sniff-tzsp sniff-target=${ip} sniff-target-port=${p.tzsp} comment=ROSDPI-DNS
/ipv6 firewall mangle add chain=forward protocol=tcp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=${ip} sniff-target-port=${p.tzsp} comment=ROSDPI-SNI
/ipv6 firewall mangle add chain=forward protocol=udp dst-port=443 connection-bytes=0-4000 action=sniff-tzsp sniff-target=${ip} sniff-target-port=${p.tzsp} comment=ROSDPI-SNI
# 3c. 开了 FastTrack 时:让每条连接的前 10KB 不走 FastTrack,握手才镜像得到(没有 FastTrack 规则时这两条什么也不改)
/ip firewall filter set [find action=fasttrack-connection] connection-bytes=10000-0
/ipv6 firewall filter set [find action=fasttrack-connection] connection-bytes=10000-0
# 4. 只读 API 账号(可选,用于主机名、WAN 速率)
/user group add name=rosdpi policy=read,rest-api,api,!write,!policy,!sensitive
/user add name=rosdpi group=rosdpi password=<强密码> address=${ip}`
@@ -470,10 +481,9 @@ const fixes = computed(() => {
out.push(`/ipv6 firewall mangle add chain=forward protocol=tcp dst-port=443 connection-bytes=0-4000 ${tail}`)
out.push(`/ipv6 firewall mangle add chain=forward protocol=udp dst-port=443 connection-bytes=0-4000 ${tail}`)
}
if (c.issues.includes('fasttrack')) {
// 每条连接的前 10KB 走正常路径(握手能被镜像),之后照常 FastTrack
out.push('/ip firewall filter set [find action=fasttrack-connection] connection-bytes=10000-0')
}
// 每条连接的前 10KB 走正常路径(握手能被镜像),之后照常 FastTrack
if (c.issues.includes('fasttrack')) out.push('/ip firewall filter set [find action=fasttrack-connection] connection-bytes=10000-0')
if (c.issues.includes('fasttrack6')) out.push('/ipv6 firewall filter set [find action=fasttrack-connection] connection-bytes=10000-0')
return [...new Set(out)]
})
const fixCopied = ref(false)