4 Commits

Author SHA1 Message Date
eli 1d5af2248b fix(firewall): forward 链改回"作用域白名单 + 默认丢弃"
之前把 forward 链清空成 policy accept 是错的——那不是标准,是相对基线的
**安全退化**。基线(init-iptables.sh)本来就是:

    -A FORWARD -o podman+ -j ACCEPT
    -A FORWARD -j REJECT

配合 net.ipv4.ip_forward=1,清空 forward 等于让主机变成转发器。

现在按基线语义实现:

    chain forward {
        type filter hook forward priority filter; policy drop;
        ct state established,related accept
        iifname/oifname "wt0" accept      # NetBird 覆盖网
        iifname/oifname "zt*" accept      # ZeroTier 覆盖网
        iifname/oifname "podman*" accept  # Podman
        iifname/oifname "docker0" accept
        iifname/oifname "br-*" accept
    }

两处必须显式列出接口的原因(都实测过):

1. **容器发布端口的入站在 forward 里没有任何现成规则可匹配**。实测
   NETAVARK_FORWARD 只有 `saddr 10.89.0.0/24 accept`(出站)和
   `daddr 10.89.0.0/24 established accept`(回程),**没有发布端口的入站
   accept**。基线是靠 `-o podman+ ACCEPT` 放行的,这里同理用 oifname 匹配。

2. **NetBird/ZeroTier 会自己往 `ip filter FORWARD` 写规则**。实测 oraclejp
   的 `ip filter FORWARD` 里有 netbird 加的 `iifname "wt0" accept`。本表的
   `policy drop` 是终局裁决,不同步放行就会把 VPN 转发打死。

验证(oraclezyus-arm):SSH/80/443/容器 9000 全通、容器 DNS 与出站正常、
容器到宿主机 443 正常。测试 77 → 79 项全绿。
2026-11-11 12:24:44 +08:00
eli 57b21d5b99 refactor(firewall): forward 链彻底不做过滤(回到 netavark 本来就能工作的状态)
之前连续两次修错方向,根因是没搞清 nftables 的多表裁决语义:

  · netavark 自己会在 `ip filter` 的 NETAVARK_FORWARD 链里放行容器流量
    (实测:`ip saddr 10.89.0.0/24 accept`,Docker 同理有 DOCKER-FORWARD);
  · 但 nftables 的 `accept` **不是终局裁决**,包会继续流到下一张表的基础链;
  · 本表在 forward 上写 reject → 把运行时已经放行的流量打死。

第一次修:加 `ct status dnat accept`(只解决外部访问发布端口,解决不了容器出站,
因为 SNAT 在 postrouting,ct status 不是 dnat)。
第二次修:再加一堆 `iifname podman*/docker0/br-*` accept。
两次都是"补规则",越补越脆弱,还踩到 nft 1.0.2 不支持通配接口名集合的坑。

正确做法是**这一条都别加**:宿主机防火墙的职责是保护本机服务(input),
转发流量本来就该由容器运行时和云安全组负责,本表不掺和。
这是社区标准结论(Red Hat KB 5885821、netavark#977:把 FORWARD 设 DROP 就会
让 Podman/Docker 连不上)。

改动:`chain forward` 只留 `type filter hook forward priority filter; policy accept;`,
删除之前的 dnat/网桥规则。黄金基线与回归测试同步改为"forward 链内不许出现 reject/drop"。

验证:容器内 DNS 解析正常、出站 301、5 台 9000/api/health 全 200、forward 链 0 条拒绝规则。
测试 77 项全绿。
2026-11-10 13:06:25 +08:00
eli 328a41fda3 fix(firewall): forward 链放行 DNAT,否则容器发布端口全被挡成 refused
从 iptables 版迁移到 nftables 版时丢了"容器转发先放行"的语义:
  · init-iptables.sh 把 reject 追加在 FORWARD 链**尾部**,Docker/Podman 会把自己的链
    插在最前面,容器流量天然先被接受;
  · nftables 版写成 `ct state established,related accept` + `reject`,而 Podman 的
    端口发布靠 NAT 的 DNAT 改写目标地址,改写后照样要过 forward 链 → 撞 reject。

症状很坑:宿主机自己 curl 127.0.0.1 正常(走 lo),外部一律 **connection refused**。
不是超时——本表用 reject 而不是 drop,所以看着像"端口根本没开",很容易往错方向查。

暴露方式:昨天把规则推到 5 台 Oracle,把这些机器上 Podman 发布的 9000(Arcane agent
的 API)打掉了,表现是 Arcane 面板里这批 VPS 全部离线。

修法:在 forward 链的 reject 之前加 `ct status dnat accept`——只放行被本机 NAT 改写过的
包,其余转发仍然拒绝。黄金基线 dsh-firewall.nft 同步更新。

补了两条回归测试:forward 链必须有该规则,且必须排在 reject 之前。
测试 75 → 77 项。
2026-11-10 11:24:37 +08:00
eli 5420ea95e3 feat(firewall): 主机防火墙收进本仓库,全机队共用
init-firewall.sh 之前落在 oci-toolkit 里,但它是"给任何一台代理节点上防火墙",
跟 OCI 没关系 —— GCP、阿里云、搬瓦工、Oracle 都要用同一份。挪到 vpsetup,
和 setup_*/migrate_* 放一起,按机器角色选 profile:

  proxy(默认) / hy2 / web / minimal

端口全走开关(--ssh-port/--hy2-port/--hy2-hop/--no-hy2-hop/--no-http3/
--extra-tcp/--extra-udp/--enable-frps/--enable-xmpp)。默认 profile 生成的
规则与现网 dsh-firewall.nft 逐条一致,老机器重跑是纯 no-op。

测试 tests/run_firewall_tests.sh 75 项,钉死:默认与现网一致、四个 profile 的
端口集合、任何组合都保留链尾 REJECT 兜底、非法输入 exit 2 且不产出规则。
OCI 那边同时删掉,避免两份分叉。
2026-11-08 00:48:17 +08:00