diff --git a/CHALLENGES.md b/CHALLENGES.md index 442b6f0..548b48a 100644 --- a/CHALLENGES.md +++ b/CHALLENGES.md @@ -34,7 +34,7 @@ The server waits until solved or defined timeout, then continues on other challe Example: ```yaml - self-preload-link: + preload-link: condition: '"Sec-Fetch-Mode" in headers && headers["Sec-Fetch-Mode"] == "navigate"' runtime: "preload-link" parameters: diff --git a/README.md b/README.md index 8a4ceed..a3920ef 100644 --- a/README.md +++ b/README.md @@ -109,16 +109,16 @@ For example: - name: standard-browser action: challenge settings: - challenges: [http-cookie-check, self-preload-link, self-meta-refresh, self-resource-load, js-pow-sha256] + challenges: [http-cookie-check, preload-link, meta-refresh, resource-load, js-pow-sha256] conditions: - '($is-generic-browser)' ``` This rule has the user be checked against a backend, then attempts pass a few browser challenges. -In this case the processing would stop at `self-meta-refresh` due to the behavior of earlier challenges (cookie check and preload link allow failing / continue due to being silent, while meta-refresh requires displaying a challenge page). +In this case the processing would stop at `meta-refresh` due to the behavior of earlier challenges (cookie check and preload link allow failing / continue due to being silent, while meta-refresh requires displaying a challenge page). -Any of these listed challenges being passed in the past will allow the client through, including non-offered `self-resource-load` and `js-pow-sha256`. +Any of these listed challenges being passed in the past will allow the client through, including non-offered `resource-load` and `js-pow-sha256`. ### Non-Javascript challenges @@ -290,7 +290,7 @@ However, a few points are left before go-away can be called v1.0.0: * [ ] Define strings and multi-language support for quick modification by operators without custom templates. * [ ] Have highly tested paths that match examples. * [ ] Caching of temporary fetches, for example, network ranges. -* [ ] Allow live and dynamic policy reloading. +* [x] Allow live and dynamic policy reloading. * [x] Multiple domains / subdomains -> one backend handling, CEL rules for backends * [ ] Merge all rules and conditions into one large AST for higher performance. * [ ] Explore exposing a module for direct Caddy usage. diff --git a/cmd/go-away/main.go b/cmd/go-away/main.go index ee5ec41..c2beb6d 100644 --- a/cmd/go-away/main.go +++ b/cmd/go-away/main.go @@ -20,11 +20,13 @@ import ( "net" "net/http" "os" + "os/signal" "path" "runtime/debug" "strconv" "strings" "sync/atomic" + "syscall" ) func setupListener(network, address, socketMode string, proxy bool) (net.Listener, string) { @@ -279,15 +281,15 @@ func main() { serverHandler.Store(&fn) } - go func() { + loadPolicyState := func() (http.Handler, error) { policyData, err := os.ReadFile(*policyFile) if err != nil { - log.Fatal(fmt.Errorf("failed to read policy file: %w", err)) + return nil, fmt.Errorf("failed to read policy file: %w", err) } p, err := policy.NewPolicy(bytes.NewReader(policyData), *policySnippets) if err != nil { - log.Fatal(fmt.Errorf("failed to parse policy file: %w", err)) + return nil, fmt.Errorf("failed to parse policy file: %w", err) } settings := policy.Settings{ @@ -305,14 +307,38 @@ func main() { state, err := lib.NewState(*p, settings) if err != nil { - log.Fatal(fmt.Errorf("failed to create state: %w", err)) + return nil, fmt.Errorf("failed to create state: %w", err) + } + return state, nil + } + + go func() { + handler, err := loadPolicyState() + if err != nil { + log.Fatal(fmt.Errorf("failed to load policy state: %w", err)) } - serverHandler.Store(&state) - + serverHandler.Store(&handler) slog.Warn( - "handler started", + "handler configuration loaded", ) + + // allow reloading from now on + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGHUP) + for sig := range c { + if sig != syscall.SIGHUP { + continue + } + handler, err = loadPolicyState() + if err != nil { + slog.Error("handler configuration reload error", "err", err) + continue + } + + serverHandler.Store(&handler) + slog.Warn("handler configuration reloaded") + } }() if tlsConfig != nil {