v0.26.1 per-client connection caps
This commit is contained in:
1 parent
ee01cb00fe
commit
cdd4fc01a7
36 files changed
+795
-417
No files matched your search
@@ -156,11 +156,15 @@ func NewHTTPSinkPlugin(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authPolicy, err := authz.New(opts.Auth, tlsCfg, authz.RoleListener, authz.HTTP)
|
||||
kind := netacl.HTTP
|
||||
if opts.Auth != nil && len(opts.Auth.TrustedProxies) > 0 {
|
||||
kind = netacl.HTTPProxied
|
||||
}
|
||||
aclPolicy, err := netacl.New(opts.ACL, opts.Host, kind, logger, "http_sink", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aclPolicy, err := netacl.New(opts.ACL, opts.Host, logger, "http_sink", id)
|
||||
authPolicy, err := authz.New(opts.Auth, tlsCfg, aclPolicy, authz.RoleListener, authz.HTTP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -264,14 +268,16 @@ func (h *HTTPSink) serve(ctx context.Context, ln net.Listener) error {
|
||||
|
||||
// One wrapper covers stream and status, and keeps the handlers themselves
|
||||
// unaware of authorization; a nil policy admits every request. Login, the
|
||||
// browser files and the root sit outside it; in proxy mode everything sits
|
||||
// behind the proxy gate.
|
||||
// browser files and the root sit outside it; all but login, which SCRAM
|
||||
// throttling limits, count in the per-client request rate. In proxy mode
|
||||
// everything sits behind the proxy gate.
|
||||
limit := func(next http.Handler) http.Handler { return h.acl.Requests(next, clientAddr) }
|
||||
outer := http.NewServeMux()
|
||||
outer.HandleFunc(http.MethodPost+" "+chain.AuthPath, h.handleAuth)
|
||||
for p, file := range h.web {
|
||||
outer.Handle(http.MethodGet+" "+p, file)
|
||||
outer.Handle(http.MethodGet+" "+p, limit(file))
|
||||
}
|
||||
outer.Handle("/", h.authMiddleware(mux))
|
||||
outer.Handle("/", limit(h.authMiddleware(mux)))
|
||||
var handler http.Handler = outer
|
||||
if h.auth.BehindProxy() {
|
||||
handler = h.proxyGate(outer)
|
||||
@@ -572,6 +578,7 @@ func (h *HTTPSink) armWrite(rc *http.ResponseController) {
|
||||
|
||||
// handleStatus provides a JSON status report
|
||||
func (h *HTTPSink) handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||
denied, limited := h.acl.Refused()
|
||||
status := map[string]any{
|
||||
"service": "LogWisp",
|
||||
"version": version.Short(),
|
||||
@@ -599,7 +606,8 @@ func (h *HTTPSink) handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||
"dropped_writes": h.droppedWrites.Load(),
|
||||
"rejected_clients": h.rejectedClients.Load(),
|
||||
"auth_rejected": h.auth.Rejected(),
|
||||
"acl_denied": h.acl.Denied(),
|
||||
"acl_denied": denied,
|
||||
"acl_limited": limited,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"embed"
|
||||
"errors"
|
||||
"html"
|
||||
"net/http"
|
||||
"path"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"github.com/lixenwraith/logwisp/internal/authz"
|
||||
"github.com/lixenwraith/logwisp/internal/chain"
|
||||
"github.com/lixenwraith/logwisp/internal/config"
|
||||
"github.com/lixenwraith/logwisp/internal/netacl"
|
||||
)
|
||||
|
||||
//go:embed web/*.js web/*.html web/*.css
|
||||
@@ -101,18 +103,21 @@ func serveWebFile(data []byte, contentType string) http.Handler {
|
||||
// clientKey carries the forwarded client address from proxyGate
|
||||
type clientKey struct{}
|
||||
|
||||
// proxyGate admits only the trusted proxies, and records the client they
|
||||
// forward for logs and sessions. ServeAuth and AuthorizeRequest check again.
|
||||
// proxyGate admits only the trusted proxies, forwarding a client the acl
|
||||
// rules admit, and records that client for logs, sessions and the request
|
||||
// rate. ServeAuth and AuthorizeRequest check again.
|
||||
func (h *HTTPSink) proxyGate(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
addr, err := h.auth.ClientAddr(r)
|
||||
if err != nil {
|
||||
h.logger.Warn("msg", "Request refused: not through a trusted proxy over https",
|
||||
"component", "http_sink",
|
||||
"instance_id", h.id,
|
||||
"remote_addr", r.RemoteAddr,
|
||||
"path", r.URL.Path,
|
||||
"error", err)
|
||||
if !errors.Is(err, netacl.ErrDenied) { // reported by netacl, once a minute
|
||||
h.logger.Warn("msg", "Request refused: not through a trusted proxy over https",
|
||||
"component", "http_sink",
|
||||
"instance_id", h.id,
|
||||
"remote_addr", r.RemoteAddr,
|
||||
"path", r.URL.Path,
|
||||
"error", err)
|
||||
}
|
||||
authz.Refuse(w, http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user