feat: rules hot reload via SIGHUP (#44)

This commit is contained in:
Toby 2024-02-03 10:55:20 -08:00 committed by GitHub
parent 8d94400855
commit f8f0153664
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 39 additions and 4 deletions

View File

@ -25,6 +25,7 @@ OpenGFW は、Linux 上の [GFW](https://en.wikipedia.org/wiki/Great_Firewall)
- フローベースのマルチコア負荷分散 - フローベースのマルチコア負荷分散
- 接続オフロード - 接続オフロード
- [expr](https://github.com/expr-lang/expr) に基づく強力なルールエンジン - [expr](https://github.com/expr-lang/expr) に基づく強力なルールエンジン
- ルールのホットリロード (`SIGHUP` を送信してリロード)
- 柔軟なアナライザ&モディファイアフレームワーク - 柔軟なアナライザ&モディファイアフレームワーク
- 拡張可能な IO 実装(今のところ NFQueue のみ) - 拡張可能な IO 実装(今のところ NFQueue のみ)
- [WIP] ウェブ UI - [WIP] ウェブ UI

View File

@ -29,6 +29,7 @@ Linux that's in many ways more powerful than the real thing. It's cyber sovereig
- Flow-based multicore load balancing - Flow-based multicore load balancing
- Connection offloading - Connection offloading
- Powerful rule engine based on [expr](https://github.com/expr-lang/expr) - Powerful rule engine based on [expr](https://github.com/expr-lang/expr)
- Hot-reloadable rules (send `SIGHUP` to reload)
- Flexible analyzer & modifier framework - Flexible analyzer & modifier framework
- Extensible IO implementation (only NFQueue for now) - Extensible IO implementation (only NFQueue for now)
- [WIP] Web UI - [WIP] Web UI

View File

@ -25,6 +25,7 @@ OpenGFW 是一个 Linux 上灵活、易用、开源的 [GFW](https://zh.wikipedi
- 基于流的多核负载均衡 - 基于流的多核负载均衡
- 连接 offloading - 连接 offloading
- 基于 [expr](https://github.com/expr-lang/expr) 的强大规则引擎 - 基于 [expr](https://github.com/expr-lang/expr) 的强大规则引擎
- 规则可以热重载 (发送 `SIGHUP` 信号)
- 灵活的协议解析和修改框架 - 灵活的协议解析和修改框架
- 可扩展的 IO 实现 (目前只有 NFQueue) - 可扩展的 IO 实现 (目前只有 NFQueue)
- [开发中] Web UI - [开发中] Web UI

View File

@ -7,6 +7,7 @@ import (
"os/signal" "os/signal"
"strconv" "strconv"
"strings" "strings"
"syscall"
"github.com/apernet/OpenGFW/analyzer" "github.com/apernet/OpenGFW/analyzer"
"github.com/apernet/OpenGFW/analyzer/tcp" "github.com/apernet/OpenGFW/analyzer/tcp"
@ -267,14 +268,42 @@ func runMain(cmd *cobra.Command, args []string) {
logger.Fatal("failed to initialize engine", zap.Error(err)) logger.Fatal("failed to initialize engine", zap.Error(err))
} }
// Signal handling
ctx, cancelFunc := context.WithCancel(context.Background()) ctx, cancelFunc := context.WithCancel(context.Background())
go func() { go func() {
sigChan := make(chan os.Signal) // Graceful shutdown
signal.Notify(sigChan, os.Interrupt, os.Kill) shutdownChan := make(chan os.Signal)
<-sigChan signal.Notify(shutdownChan, os.Interrupt, os.Kill)
<-shutdownChan
logger.Info("shutting down gracefully...") logger.Info("shutting down gracefully...")
cancelFunc() cancelFunc()
}() }()
go func() {
// Rule reload
reloadChan := make(chan os.Signal)
signal.Notify(reloadChan, syscall.SIGHUP)
for {
<-reloadChan
logger.Info("reloading rules")
rawRs, err := ruleset.ExprRulesFromYAML(args[0])
if err != nil {
logger.Error("failed to load rules, using old rules", zap.Error(err))
continue
}
rs, err := ruleset.CompileExprRules(rawRs, analyzers, modifiers, rsConfig)
if err != nil {
logger.Error("failed to compile rules, using old rules", zap.Error(err))
continue
}
err = en.UpdateRuleset(rs)
if err != nil {
logger.Error("failed to update ruleset", zap.Error(err))
} else {
logger.Info("rules reloaded")
}
}
}()
logger.Info("engine started") logger.Info("engine started")
logger.Info("engine exited", zap.Error(en.Run(ctx))) logger.Info("engine exited", zap.Error(en.Run(ctx)))
} }

View File

@ -127,7 +127,10 @@ func (w *worker) Run(ctx context.Context) {
} }
func (w *worker) UpdateRuleset(r ruleset.Ruleset) error { func (w *worker) UpdateRuleset(r ruleset.Ruleset) error {
return w.tcpStreamFactory.UpdateRuleset(r) if err := w.tcpStreamFactory.UpdateRuleset(r); err != nil {
return err
}
return w.udpStreamFactory.UpdateRuleset(r)
} }
func (w *worker) handle(streamID uint32, p gopacket.Packet) (io.Verdict, []byte) { func (w *worker) handle(streamID uint32, p gopacket.Packet) (io.Verdict, []byte) {