diff --git a/docs/changelog/index.md b/docs/changelog/index.md index 94098a6a..cc2ab20e 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -23,6 +23,7 @@ sidebar: false ### 修复 +- 修复代理路由详情页点击“发布配置”时,同时弹出配置差异对话框和确认发布对话框导致重叠的问题:点击发布时不再展示配置差异,直接进行确认发布。 - 修复配置版本发布到 Agent 后 `openresty -t` 因 `proxy_cache_path` 使用 `/var/cache/openresty` 导致非 root 用户 `mkdir` 失败的问题:发布快照与渲染将 `/var/` 下路径规范为 `__OPENFLARE_PROXY_CACHE_PATH__`,Agent 应用时落地为 `data_dir/var/cache/openflare_proxy` 并兼容重写已发布配置中的旧路径。 - 修复配置版本发布到 Agent 后 `openresty -t` 因证书私钥无法解析而失败的问题。根因是发布快照生成 `certs/{id}.key` 时直接写入库内加密的 `KeyPEM`(`enc:v1:`),未解密为 PEM;现与证书详情接口一致,发布前通过 `OpenKeyPEM` 解密后再下发。 - 修复 `/api/v1/d/option` 批量更新 OpenResty 等业务配置不生效的问题。根本原因是 option 模块在读写时做了 PascalCase 与 snake_case 的机械转换(如 `OpenRestyEventsUse` → `open_resty_events_use`),与 `w_system_configs` 中实际 key(`openresty_events_use`)不一致,更新写入了错误的幽灵配置行。现改为 API 直接使用与数据库一致的 snake_case key,并同步更新前端性能调优与运维设置页。 @@ -30,6 +31,8 @@ sidebar: false - 修复 openflared(Tunnel Client)WebSocket 连接在 Cloudflare 代理环境下频繁收到 EOF 断连的问题。根本原因:服务端 `read_pump` 仅在收到 WebSocket 协议层 Pong 帧时刷新读超时,而客户端(`golang.org/x/net/websocket`)以 JSON 应用层 `{"type":"pong"}` 响应 ping,服务端 90s 读超时到期后主动关闭连接,客户端收到 EOF 并进入无限重连循环。修复方式:在 `clientPongType` 分支中同步调用 `conn.SetReadDeadline` 刷新超时。 - 修复 openflared frpc 子进程异常退出(`exit status 1`)时缺乏详细诊断信息的问题。现捕获 frpc stderr 并在进程退出时将其输出记录到结构化日志 `stderr` 字段,便于排查配置格式错误、Auth Token 鉴权失败、relay 端不可达等具体原因。 - 修复 Relay 节点启动时在双栈网络环境可能上报 IPv6 地址,导致 Tunnel frpc 客户端无法连接 frps 的问题。强化 `pkg/geoip.HTTPOutboundIPStrategy` 在回退到双栈客户端后仍优先返回 IPv4 地址,确保 Relay 心跳上报的 IP 与 frpc 连接兼容。 +- 修复 WAF 黑白名单判定时,白名单作为严格准入控制导致黑名单逻辑失效的问题。现将白名单逻辑调整为信任放行(Bypass/Allow),命中的请求直接放行,未命中的请求继续进入黑名单等防护模块判定。 +- 修复 WAF IP 组手动编辑和配置版本发布后,未向 Agent 触发 WebSocket 实时广播导致配置变更不能即时生效的问题。 ### 变更 diff --git a/internal/apps/agent/nginx/manager_test.go b/internal/apps/agent/nginx/manager_test.go index 342bc9ad..06c805b7 100644 --- a/internal/apps/agent/nginx/manager_test.go +++ b/internal/apps/agent/nginx/manager_test.go @@ -699,15 +699,12 @@ func TestManagedPowLuaFilesUseInternalChallengeFlow(t *testing.T) { } } -func TestManagedWAFLuaTreatsWhitelistAsAllowlist(t *testing.T) { - if !strings.Contains(openRestyWAFRuntimeLua, "local function first_allowlist_group(groups)") { - t.Fatal("expected waf runtime to detect allowlist rule groups") +func TestManagedWAFLuaTreatsWhitelistAsBypass(t *testing.T) { + if !strings.Contains(openRestyWAFRuntimeLua, "if ip_matches(group.ip_whitelist, ip)") { + t.Fatal("expected waf runtime to bypass request when ip matches whitelist") } - if !strings.Contains(openRestyWAFRuntimeLua, "local allowlist_group = first_allowlist_group(groups)") { - t.Fatal("expected waf runtime to enter allowlist mode when whitelist rules exist") - } - if !strings.Contains(openRestyWAFRuntimeLua, "return exit_with_group(allowlist_group)") { - t.Fatal("expected waf runtime to block requests that miss configured whitelists") + if strings.Contains(openRestyWAFRuntimeLua, "first_allowlist_group") { + t.Fatal("expected waf runtime not to block requests that miss configured whitelists") } } diff --git a/internal/apps/agent/nginx/waf_assets.go b/internal/apps/agent/nginx/waf_assets.go index 8b7d12bc..b8d7e8fe 100644 --- a/internal/apps/agent/nginx/waf_assets.go +++ b/internal/apps/agent/nginx/waf_assets.go @@ -219,17 +219,6 @@ local function exit_with_group(group) return ngx.exit(ngx.status) end -local function first_allowlist_group(groups) - for _, group in ipairs(groups) do - if table_has_items(group.ip_whitelist) - or table_has_items(group.ip_whitelist_group_ids) - or table_has_items(group.country_whitelist) then - return group - end - end - return nil -end - local config = load_config() if not config then if config_dict:add("_missing_config_logged", true, 60) then @@ -264,11 +253,6 @@ for _, group in ipairs(groups) do end end -local allowlist_group = first_allowlist_group(groups) -if allowlist_group then - return exit_with_group(allowlist_group) -end - for _, group in ipairs(groups) do if ip_matches(group.ip_blacklist, ip) or ip_matches_group_ids(group.ip_blacklist_group_ids, ip, ip_groups_config) then return exit_with_group(group) diff --git a/internal/apps/openflare/config_version/logics.go b/internal/apps/openflare/config_version/logics.go index d7755ad0..a653d6cd 100644 --- a/internal/apps/openflare/config_version/logics.go +++ b/internal/apps/openflare/config_version/logics.go @@ -15,7 +15,9 @@ import ( "time" "github.com/Rain-kl/Wavelet/internal/apps/openflare/routeidentity" + "github.com/Rain-kl/Wavelet/internal/apps/openflare/websocket" "github.com/Rain-kl/Wavelet/internal/model" + pkgprotocol "github.com/Rain-kl/Wavelet/pkg/protocol" openrestyrender "github.com/Rain-kl/Wavelet/pkg/render/openresty" "gorm.io/gorm" ) @@ -233,6 +235,10 @@ func PublishConfigVersion(ctx context.Context, createdBy string, force bool) (*m } return nil, err } + websocket.BroadcastActiveConfig(pkgprotocol.ActiveConfigMeta{ + Version: record.Version, + Checksum: record.Checksum, + }) return record, nil } @@ -246,6 +252,10 @@ func ActivateConfigVersion(ctx context.Context, id uint) (*model.ConfigVersion, return nil, err } version.IsActive = true + websocket.BroadcastActiveConfig(pkgprotocol.ActiveConfigMeta{ + Version: version.Version, + Checksum: version.Checksum, + }) return version, nil } diff --git a/internal/apps/openflare/waf/logics.go b/internal/apps/openflare/waf/logics.go index 8d9cae07..180f1604 100644 --- a/internal/apps/openflare/waf/logics.go +++ b/internal/apps/openflare/waf/logics.go @@ -454,6 +454,7 @@ func CreateIPGroup(ctx context.Context, input IPGroupInput) (*IPGroupView, error if err = model.CreateOpenFlareWAFIPGroup(ctx, group); err != nil { return nil, err } + broadcastIPGroupToAgents(ctx, group.ID) return GetIPGroup(ctx, group.ID) } @@ -470,6 +471,7 @@ func UpdateIPGroup(ctx context.Context, id uint, input IPGroupInput) (*IPGroupVi if err = model.UpdateOpenFlareWAFIPGroup(ctx, group); err != nil { return nil, err } + broadcastIPGroupToAgents(ctx, group.ID) return GetIPGroup(ctx, group.ID) } diff --git a/internal/apps/openflare/websocket/agent_hub.go b/internal/apps/openflare/websocket/agent_hub.go index 5bc306bd..1dfe27a1 100644 --- a/internal/apps/openflare/websocket/agent_hub.go +++ b/internal/apps/openflare/websocket/agent_hub.go @@ -152,6 +152,28 @@ func BroadcastWAFIPGroups(payload any) int { return success } +// BroadcastActiveConfig pushes active config metadata to all connected agents. +func BroadcastActiveConfig(payload any) int { + if payload == nil { + return 0 + } + message := Message{Type: agentMessageTypeActiveConfig, Payload: payload} + defaultAgentHub.mu.RLock() + clients := make([]*agentClient, 0, len(defaultAgentHub.clients)) + for _, client := range defaultAgentHub.clients { + clients = append(clients, client) + } + defaultAgentHub.mu.RUnlock() + + success := 0 + for _, client := range clients { + if client.enqueue(message) { + success++ + } + } + return success +} + // SendForceSyncConfig notifies an agent to force sync configuration. func SendForceSyncConfig(nodeID string, payload any) bool { return sendAgentMessage(nodeID, Message{Type: agentMessageTypeForceSyncConfig, Payload: payload})