From aa66978bbd1b633b6feb6a4abc1d0b9f9c822a58 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 22:05:29 +0100 Subject: [PATCH 01/16] added ipfilter middleware for trusted and blocked ips --- internals/proxy/middlewares/ipfilter.go | 95 +++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 internals/proxy/middlewares/ipfilter.go diff --git a/internals/proxy/middlewares/ipfilter.go b/internals/proxy/middlewares/ipfilter.go new file mode 100644 index 00000000..af3c0662 --- /dev/null +++ b/internals/proxy/middlewares/ipfilter.go @@ -0,0 +1,95 @@ +package middlewares + +import ( + "net" + "net/http" + "slices" + "strings" + + "github.com/codeshelldev/gotl/pkg/logger" +) + +var IPFilter Middleware = Middleware{ + Name: "IP Filter", + Use: ipFilterHandler, +} + +var trustedClientKey contextKey = "isClientTrusted" + +func ipFilterHandler(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + conf := getConfigByReq(req) + + ipFilter := conf.SETTINGS.ACCESS.IP_FILTER + + if ipFilter == nil { + ipFilter = getConfig("").SETTINGS.ACCESS.ENDPOINTS + } + + ip := getContext[net.IP](req, clientIPKey) + + block, trusted := blockIPOrTrust(ip, ipFilter) + + if block { + logger.Warn("Client IP is blocked by filter: ", ip.String()) + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + + if trusted { + logger.Dev("Connection from trusted Client: ", ip.String()) + } + + req = setContext(req, trustedClientKey, trusted) + + next.ServeHTTP(w, req) + }) +} + +func getIPNets(ipNets []string) ([]string, []string) { + blockedIPNets := []string{} + allowedIPNets := []string{} + + for _, ipNet := range ipNets { + ip, block := strings.CutPrefix(ipNet, "!") + + if block { + blockedIPNets = append(blockedIPNets, ip) + } else { + allowedIPNets = append(allowedIPNets, ip) + } + } + + return allowedIPNets, blockedIPNets +} + +func blockIPOrTrust(ip net.IP, ipfilter []string) (bool, bool) { + if len(ipfilter) == 0 { + // default: allow all, but do not trust + return false, false + } + + rawAllowed, rawBlocked := getIPNets(ipfilter) + + allowed := parseIPsAndIPNets(rawAllowed) + blocked := parseIPsAndIPNets(rawBlocked) + + isExplicitlyAllowed := slices.ContainsFunc(allowed, func(try *net.IPNet) bool { + return try.Contains(ip) + }) + isExplicitlyBlocked := slices.ContainsFunc(blocked, func(try *net.IPNet) bool { + return try.Contains(ip) + }) + + // explicit allow > block + if isExplicitlyAllowed { + return false, true + } + + if isExplicitlyBlocked { + return true, false + } + + // default: allow all, but do not trust + return false, false +} From 328154173de5d0c66fddcd41b016520dd816bc5b Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 22:05:48 +0100 Subject: [PATCH 02/16] added proxy middleware for ip resolving and trusted proxies --- internals/proxy/middlewares/proxy.go | 140 +++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 internals/proxy/middlewares/proxy.go diff --git a/internals/proxy/middlewares/proxy.go b/internals/proxy/middlewares/proxy.go new file mode 100644 index 00000000..2650b2fc --- /dev/null +++ b/internals/proxy/middlewares/proxy.go @@ -0,0 +1,140 @@ +package middlewares + +import ( + "errors" + "net" + "net/http" + "strings" + + "github.com/codeshelldev/gotl/pkg/logger" +) + +var InternalProxy Middleware = Middleware{ + Name: "_Proxy", + Use: proxyHandler, +} + +const trustedProxyKey contextKey = "isProxyTrusted" +const clientIPKey contextKey = "clientIP" + +func proxyHandler(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + conf := getConfigByReq(req) + + rawTrustedProxies := conf.SETTINGS.ACCESS.TRUSTED_PROXIES + + var trusted bool + var ip net.IP + + if len(rawTrustedProxies) != 0 { + host, _, _ := net.SplitHostPort(req.RemoteAddr) + + ip = net.ParseIP(host) + + if ip != nil { + trustedProxies := parseIPsAndIPNets(rawTrustedProxies) + + trusted = isTrustedProxy(ip, trustedProxies) + } + } + + if trusted { + realIP, err := getRealIP(req) + + if err != nil { + logger.Error("Could not get real IP: ", err.Error()) + } + + if realIP != nil { + ip = realIP + } + } + + req = setContext(req, clientIPKey, ip) + req = setContext(req, trustedProxyKey, trusted) + + next.ServeHTTP(w, req) + }) +} + +func parseIP(str string) (*net.IPNet, error) { + if !strings.Contains(str, "/") { + ip := net.ParseIP(str) + + if ip == nil { + return nil, errors.New("invalid ip: " + str) + } + + var mask net.IPMask + + if ip.To4() != nil { + mask = net.CIDRMask(32, 32) // IPv4 /32 + } else { + mask = net.CIDRMask(128, 128) // IPv6 /128 + } + + return &net.IPNet{IP: ip, Mask: mask}, nil + } + + ip, network, err := net.ParseCIDR(str) + if err != nil { + return nil, err + } + + if !ip.Equal(network.IP) { + var mask net.IPMask + + if ip.To4() != nil { + mask = net.CIDRMask(32, 32) // IPv4 /32 + } else { + mask = net.CIDRMask(128, 128) // IPv6 /128 + } + + return &net.IPNet{IP: ip, Mask: mask}, nil + } + + return network, nil +} + +func parseIPsAndIPNets(array []string) []*net.IPNet { + ipNets := []*net.IPNet{} + + for _, item := range array { + ipNet, err := parseIP(item) + + if err != nil { + continue + } + + ipNets = append(ipNets, ipNet) + } + + return ipNets +} + +func getRealIP(req *http.Request) (net.IP, error) { + XFF := req.Header.Get("X-Forwarded-For") + + if XFF != "" { + ips := strings.Split(XFF, ",") + + realIP := net.ParseIP(strings.TrimSpace(ips[0])) + + if realIP == nil { + return nil, errors.New("malformed x-forwarded-for header") + } + + return realIP, nil + } + + return nil, errors.New("no x-forwarded-for header present") +} + +func isTrustedProxy(ip net.IP, proxies []*net.IPNet) bool { + for _, net := range proxies { + if net.Contains(ip) { + return true + } + } + return false +} \ No newline at end of file From 78bcbf27409d55428bb82bd8d831109787d3a899 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 22:05:58 +0100 Subject: [PATCH 03/16] register middlewares --- internals/proxy/proxy.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internals/proxy/proxy.go b/internals/proxy/proxy.go index aae6345f..d0d17aea 100644 --- a/internals/proxy/proxy.go +++ b/internals/proxy/proxy.go @@ -31,10 +31,12 @@ func Create(targetUrl string) Proxy { func (proxy Proxy) Init() http.Handler { handler := m.NewChain(). + Use(m.InternalProxy). Use(m.Server). Use(m.Auth). Use(m.RequestLogger). Use(m.InternalAuthRequirement). + Use(m.IPFilter). Use(m.Port). Use(m.RateLimit). Use(m.Template). From 8360169c541eb9f85abd18b33fb1d0b2a10cc088 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 22:06:09 +0100 Subject: [PATCH 04/16] bypass rate limit for trusted clients --- internals/proxy/middlewares/ratelimit.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internals/proxy/middlewares/ratelimit.go b/internals/proxy/middlewares/ratelimit.go index 775b3c00..564f4b4b 100644 --- a/internals/proxy/middlewares/ratelimit.go +++ b/internals/proxy/middlewares/ratelimit.go @@ -35,6 +35,13 @@ func ratelimitHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { logger := getLogger(req) + trusted := getContext[bool](req, trustedClientKey) + + if trusted { + next.ServeHTTP(w, req) + return + } + conf := getConfigByReq(req) rateLimiting := conf.SETTINGS.ACCESS.RATE_LIMITING From 15bfd55a0d6f2b4950a5e14b3bf9318ace21866b Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 22:06:26 +0100 Subject: [PATCH 05/16] add configs for ipfilter and trustedProxies --- internals/config/structure/structure.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internals/config/structure/structure.go b/internals/config/structure/structure.go index 3b39cab0..52ba7512 100644 --- a/internals/config/structure/structure.go +++ b/internals/config/structure/structure.go @@ -49,6 +49,8 @@ type ACCESS struct { ENDPOINTS []string `koanf:"endpoints"` FIELD_POLICIES map[string]FieldPolicy `koanf:"fieldpolicies" childtransform:"default"` RATE_LIMITING RateLimiting `koanf:"ratelimiting"` + IP_FILTER []string `koanf:"ipfilter"` + TRUSTED_PROXIES []string `koanf:"trustedproxies"` } type FieldPolicy struct { From f898c277d038637590e6cbaee48266d4bcc8aedd Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 22:06:49 +0100 Subject: [PATCH 06/16] use `Client` instead of `User` in logs --- internals/config/tokens.go | 2 +- internals/proxy/middlewares/auth.go | 2 +- internals/proxy/middlewares/endpoints.go | 2 +- internals/proxy/middlewares/log.go | 9 ++++++--- internals/proxy/middlewares/policy.go | 2 +- internals/proxy/middlewares/port.go | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/internals/config/tokens.go b/internals/config/tokens.go index 6fb44532..c904cd80 100644 --- a/internals/config/tokens.go +++ b/internals/config/tokens.go @@ -66,7 +66,7 @@ func InitTokens() { ENV.INSECURE = true - // Set Blocked Endpoints on Config to User Layer Value + // Set Blocked Endpoints on Config to Client Layer Value // => effectively ignoring Default Layer DEFAULT.SETTINGS.ACCESS.ENDPOINTS = userConf.Layer.Strings("settings.access.endpoints") } diff --git a/internals/proxy/middlewares/auth.go b/internals/proxy/middlewares/auth.go index a6757d33..58d7af47 100644 --- a/internals/proxy/middlewares/auth.go +++ b/internals/proxy/middlewares/auth.go @@ -274,7 +274,7 @@ func (chain *AuthChain) Eval(w http.ResponseWriter, req *http.Request, tokens [] token, err = method.Authenticate(w, req, tokens) if err != nil { - logger.Warn("User failed ", method.Name, " auth: ", err.Error()) + logger.Warn("Client failed ", method.Name, " auth: ", err.Error()) } if token != "" { diff --git a/internals/proxy/middlewares/endpoints.go b/internals/proxy/middlewares/endpoints.go index 707ef844..bee8f6b1 100644 --- a/internals/proxy/middlewares/endpoints.go +++ b/internals/proxy/middlewares/endpoints.go @@ -27,7 +27,7 @@ func endpointsHandler(next http.Handler) http.Handler { reqPath := req.URL.Path if isBlocked(reqPath, endpoints) { - logger.Warn("User tried to access blocked endpoint: ", reqPath) + logger.Warn("Client tried to access blocked endpoint: ", reqPath) http.Error(w, "Forbidden", http.StatusForbidden) return } diff --git a/internals/proxy/middlewares/log.go b/internals/proxy/middlewares/log.go index 96fe536c..78b6aeab 100644 --- a/internals/proxy/middlewares/log.go +++ b/internals/proxy/middlewares/log.go @@ -1,6 +1,7 @@ package middlewares import ( + "net" "net/http" "strings" @@ -49,15 +50,17 @@ func loggingHandler(next http.Handler) http.Handler { req = setContext(req, loggerKey, l) + ip := getContext[net.IPNet](req, clientIPKey) + if !l.IsDev() { - l.Info(req.Method, " ", req.URL.Path, " ", req.URL.RawQuery) + l.Info(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery) } else { body, _ := request.GetReqBody(req) if body.Data != nil && !body.Empty { - l.Dev(req.Method, " ", req.URL.Path, " ", req.URL.RawQuery, body.Data) + l.Dev(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery, body.Data) } else { - l.Info(req.Method, " ", req.URL.Path, " ", req.URL.RawQuery) + l.Info(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery) } } diff --git a/internals/proxy/middlewares/policy.go b/internals/proxy/middlewares/policy.go index bb00ab23..08fbe112 100644 --- a/internals/proxy/middlewares/policy.go +++ b/internals/proxy/middlewares/policy.go @@ -43,7 +43,7 @@ func policyHandler(next http.Handler) http.Handler { shouldBlock, field := doBlock(body.Data, headerData, policies) if shouldBlock { - logger.Warn("User tried to use blocked field: ", field) + logger.Warn("Client tried to use blocked field: ", field) http.Error(w, "Forbidden", http.StatusForbidden) return } diff --git a/internals/proxy/middlewares/port.go b/internals/proxy/middlewares/port.go index 716e04a3..84d30d9f 100644 --- a/internals/proxy/middlewares/port.go +++ b/internals/proxy/middlewares/port.go @@ -34,7 +34,7 @@ func portHandler(next http.Handler) http.Handler { } if port != allowedPort { - logger.Warn("User tried using Token on wrong Port") + logger.Warn("Client tried using Token on wrong Port") onUnauthorized(w) return } From a40de5c3100021f62cabb44e5557f68f0e06caed Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 23:22:31 +0100 Subject: [PATCH 07/16] fix ip resolving and fix middleware order --- internals/proxy/middlewares/ipfilter.go | 4 ++++ internals/proxy/middlewares/proxy.go | 18 +++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/internals/proxy/middlewares/ipfilter.go b/internals/proxy/middlewares/ipfilter.go index af3c0662..753c4e35 100644 --- a/internals/proxy/middlewares/ipfilter.go +++ b/internals/proxy/middlewares/ipfilter.go @@ -22,6 +22,8 @@ func ipFilterHandler(next http.Handler) http.Handler { ipFilter := conf.SETTINGS.ACCESS.IP_FILTER + logger.Dev(ipFilter) + if ipFilter == nil { ipFilter = getConfig("").SETTINGS.ACCESS.ENDPOINTS } @@ -30,6 +32,8 @@ func ipFilterHandler(next http.Handler) http.Handler { block, trusted := blockIPOrTrust(ip, ipFilter) + logger.Dev(block, trusted) + if block { logger.Warn("Client IP is blocked by filter: ", ip.String()) http.Error(w, "Forbidden", http.StatusForbidden) diff --git a/internals/proxy/middlewares/proxy.go b/internals/proxy/middlewares/proxy.go index 2650b2fc..ddd1a42a 100644 --- a/internals/proxy/middlewares/proxy.go +++ b/internals/proxy/middlewares/proxy.go @@ -23,19 +23,21 @@ func proxyHandler(next http.Handler) http.Handler { rawTrustedProxies := conf.SETTINGS.ACCESS.TRUSTED_PROXIES + if rawTrustedProxies == nil { + rawTrustedProxies = getConfig("").SETTINGS.ACCESS.TRUSTED_PROXIES + } + var trusted bool var ip net.IP - if len(rawTrustedProxies) != 0 { - host, _, _ := net.SplitHostPort(req.RemoteAddr) + host, _, _ := net.SplitHostPort(req.RemoteAddr) - ip = net.ParseIP(host) + ip = net.ParseIP(host) - if ip != nil { - trustedProxies := parseIPsAndIPNets(rawTrustedProxies) + if len(rawTrustedProxies) != 0 { + trustedProxies := parseIPsAndIPNets(rawTrustedProxies) - trusted = isTrustedProxy(ip, trustedProxies) - } + trusted = isTrustedProxy(ip, trustedProxies) } if trusted { @@ -53,6 +55,8 @@ func proxyHandler(next http.Handler) http.Handler { req = setContext(req, clientIPKey, ip) req = setContext(req, trustedProxyKey, trusted) + logger.Dev(ip.String(), trusted) + next.ServeHTTP(w, req) }) } From 1c30749ed58c1b8057e296414de964ce2ff42abc Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 23:22:35 +0100 Subject: [PATCH 08/16] + --- internals/proxy/proxy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internals/proxy/proxy.go b/internals/proxy/proxy.go index d0d17aea..e1bccfa6 100644 --- a/internals/proxy/proxy.go +++ b/internals/proxy/proxy.go @@ -31,9 +31,9 @@ func Create(targetUrl string) Proxy { func (proxy Proxy) Init() http.Handler { handler := m.NewChain(). - Use(m.InternalProxy). Use(m.Server). Use(m.Auth). + Use(m.InternalProxy). Use(m.RequestLogger). Use(m.InternalAuthRequirement). Use(m.IPFilter). From 4fefb320a0108974707a441cd880e941d72ff6c8 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 23:29:48 +0100 Subject: [PATCH 09/16] fix logging middleware with incorrect context type --- internals/proxy/middlewares/log.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internals/proxy/middlewares/log.go b/internals/proxy/middlewares/log.go index 78b6aeab..34712769 100644 --- a/internals/proxy/middlewares/log.go +++ b/internals/proxy/middlewares/log.go @@ -50,7 +50,7 @@ func loggingHandler(next http.Handler) http.Handler { req = setContext(req, loggerKey, l) - ip := getContext[net.IPNet](req, clientIPKey) + ip := getContext[net.IP](req, clientIPKey) if !l.IsDev() { l.Info(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery) From 9a936ba25967b87f80e87e19e0cc91c389128672 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 23:43:53 +0100 Subject: [PATCH 10/16] imrprove middleware ordering for logger --- internals/config/structure/structure.go | 1 + internals/proxy/middlewares/clientip.go | 40 ++++++++++++++++++++++++ internals/proxy/middlewares/ipfilter.go | 40 ++++++++++++------------ internals/proxy/middlewares/log.go | 41 ++++++++++++++++--------- internals/proxy/middlewares/proxy.go | 12 +++----- internals/proxy/proxy.go | 2 ++ 6 files changed, 95 insertions(+), 41 deletions(-) create mode 100644 internals/proxy/middlewares/clientip.go diff --git a/internals/config/structure/structure.go b/internals/config/structure/structure.go index 52ba7512..2052c11a 100644 --- a/internals/config/structure/structure.go +++ b/internals/config/structure/structure.go @@ -50,6 +50,7 @@ type ACCESS struct { FIELD_POLICIES map[string]FieldPolicy `koanf:"fieldpolicies" childtransform:"default"` RATE_LIMITING RateLimiting `koanf:"ratelimiting"` IP_FILTER []string `koanf:"ipfilter"` + TRUSTED_IPS []string `koanf:"trustedips"` TRUSTED_PROXIES []string `koanf:"trustedproxies"` } diff --git a/internals/proxy/middlewares/clientip.go b/internals/proxy/middlewares/clientip.go new file mode 100644 index 00000000..11126c2a --- /dev/null +++ b/internals/proxy/middlewares/clientip.go @@ -0,0 +1,40 @@ +package middlewares + +import ( + "net" + "net/http" +) + +var InternalClientIP Middleware = Middleware{ + Name: "_Client_IP", + Use: clientIPHandler, +} + +var trustedClientKey contextKey = "isClientTrusted" + +func clientIPHandler(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + logger := getLogger(req) + + conf := getConfigByReq(req) + + rawTrustedIPs := conf.SETTINGS.ACCESS.TRUSTED_IPS + + if rawTrustedIPs == nil { + rawTrustedIPs = getConfig("").SETTINGS.ACCESS.TRUSTED_IPS + } + + ip := getContext[net.IP](req, clientIPKey) + + trustedIPs := parseIPsAndIPNets(rawTrustedIPs) + trusted := isIPInList(ip, trustedIPs) + + if trusted { + logger.Dev("Connection from trusted Client: ", ip.String()) + } + + req = setContext(req, trustedClientKey, trusted) + + next.ServeHTTP(w, req) + }) +} \ No newline at end of file diff --git a/internals/proxy/middlewares/ipfilter.go b/internals/proxy/middlewares/ipfilter.go index 753c4e35..ad392db7 100644 --- a/internals/proxy/middlewares/ipfilter.go +++ b/internals/proxy/middlewares/ipfilter.go @@ -5,8 +5,6 @@ import ( "net/http" "slices" "strings" - - "github.com/codeshelldev/gotl/pkg/logger" ) var IPFilter Middleware = Middleware{ @@ -14,10 +12,10 @@ var IPFilter Middleware = Middleware{ Use: ipFilterHandler, } -var trustedClientKey contextKey = "isClientTrusted" - func ipFilterHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + logger := getLogger(req) + conf := getConfigByReq(req) ipFilter := conf.SETTINGS.ACCESS.IP_FILTER @@ -30,9 +28,7 @@ func ipFilterHandler(next http.Handler) http.Handler { ip := getContext[net.IP](req, clientIPKey) - block, trusted := blockIPOrTrust(ip, ipFilter) - - logger.Dev(block, trusted) + block := blockIP(ip, ipFilter) if block { logger.Warn("Client IP is blocked by filter: ", ip.String()) @@ -40,12 +36,6 @@ func ipFilterHandler(next http.Handler) http.Handler { return } - if trusted { - logger.Dev("Connection from trusted Client: ", ip.String()) - } - - req = setContext(req, trustedClientKey, trusted) - next.ServeHTTP(w, req) }) } @@ -67,10 +57,10 @@ func getIPNets(ipNets []string) ([]string, []string) { return allowedIPNets, blockedIPNets } -func blockIPOrTrust(ip net.IP, ipfilter []string) (bool, bool) { +func blockIP(ip net.IP, ipfilter []string) (bool) { if len(ipfilter) == 0 { - // default: allow all, but do not trust - return false, false + // default: allow all + return false } rawAllowed, rawBlocked := getIPNets(ipfilter) @@ -87,13 +77,23 @@ func blockIPOrTrust(ip net.IP, ipfilter []string) (bool, bool) { // explicit allow > block if isExplicitlyAllowed { - return false, true + return false } if isExplicitlyBlocked { - return true, false + return true + } + + // only allowed ips -> block anything not allowed + if len(allowed) > 0 && len(blocked) == 0 { + return true + } + + // only blocked ips -> allow anything not blocked + if len(blocked) > 0 && len(allowed) == 0 { + return false } - // default: allow all, but do not trust - return false, false + // default: allow all + return false } diff --git a/internals/proxy/middlewares/log.go b/internals/proxy/middlewares/log.go index 34712769..116702e2 100644 --- a/internals/proxy/middlewares/log.go +++ b/internals/proxy/middlewares/log.go @@ -18,6 +18,33 @@ var RequestLogger Middleware = Middleware{ const loggerKey contextKey = "logger" func loggingHandler(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + logger := getLogger(req) + + ip := getContext[net.IP](req, clientIPKey) + + if !logger.IsDev() { + logger.Info(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery) + } else { + body, _ := request.GetReqBody(req) + + if body.Data != nil && !body.Empty { + logger.Dev(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery, body.Data) + } else { + logger.Info(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery) + } + } + + next.ServeHTTP(w, req) + }) +} + +var InternalMiddlewareLogger Middleware = Middleware{ + Name: "_Middleware_Logger", + Use: middlewareLoggerHandler, +} + +func middlewareLoggerHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { conf := getConfigByReq(req) @@ -50,20 +77,6 @@ func loggingHandler(next http.Handler) http.Handler { req = setContext(req, loggerKey, l) - ip := getContext[net.IP](req, clientIPKey) - - if !l.IsDev() { - l.Info(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery) - } else { - body, _ := request.GetReqBody(req) - - if body.Data != nil && !body.Empty { - l.Dev(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery, body.Data) - } else { - l.Info(ip.String(), " ", req.Method, " ", req.URL.Path, " ", req.URL.RawQuery) - } - } - next.ServeHTTP(w, req) }) } \ No newline at end of file diff --git a/internals/proxy/middlewares/proxy.go b/internals/proxy/middlewares/proxy.go index ddd1a42a..6762bfe2 100644 --- a/internals/proxy/middlewares/proxy.go +++ b/internals/proxy/middlewares/proxy.go @@ -5,8 +5,6 @@ import ( "net" "net/http" "strings" - - "github.com/codeshelldev/gotl/pkg/logger" ) var InternalProxy Middleware = Middleware{ @@ -19,6 +17,8 @@ const clientIPKey contextKey = "clientIP" func proxyHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + logger := getLogger(req) + conf := getConfigByReq(req) rawTrustedProxies := conf.SETTINGS.ACCESS.TRUSTED_PROXIES @@ -37,7 +37,7 @@ func proxyHandler(next http.Handler) http.Handler { if len(rawTrustedProxies) != 0 { trustedProxies := parseIPsAndIPNets(rawTrustedProxies) - trusted = isTrustedProxy(ip, trustedProxies) + trusted = isIPInList(ip, trustedProxies) } if trusted { @@ -55,8 +55,6 @@ func proxyHandler(next http.Handler) http.Handler { req = setContext(req, clientIPKey, ip) req = setContext(req, trustedProxyKey, trusted) - logger.Dev(ip.String(), trusted) - next.ServeHTTP(w, req) }) } @@ -134,8 +132,8 @@ func getRealIP(req *http.Request) (net.IP, error) { return nil, errors.New("no x-forwarded-for header present") } -func isTrustedProxy(ip net.IP, proxies []*net.IPNet) bool { - for _, net := range proxies { +func isIPInList(ip net.IP, list []*net.IPNet) bool { + for _, net := range list { if net.Contains(ip) { return true } diff --git a/internals/proxy/proxy.go b/internals/proxy/proxy.go index e1bccfa6..d532707c 100644 --- a/internals/proxy/proxy.go +++ b/internals/proxy/proxy.go @@ -33,7 +33,9 @@ func (proxy Proxy) Init() http.Handler { handler := m.NewChain(). Use(m.Server). Use(m.Auth). + Use(m.InternalMiddlewareLogger). Use(m.InternalProxy). + Use(m.InternalClientIP). Use(m.RequestLogger). Use(m.InternalAuthRequirement). Use(m.IPFilter). From bce57f5674037c902e721e4e350b87b52022a322 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 23:53:22 +0100 Subject: [PATCH 11/16] debugging ip blocking --- internals/proxy/middlewares/ipfilter.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/internals/proxy/middlewares/ipfilter.go b/internals/proxy/middlewares/ipfilter.go index ad392db7..6647da55 100644 --- a/internals/proxy/middlewares/ipfilter.go +++ b/internals/proxy/middlewares/ipfilter.go @@ -5,6 +5,8 @@ import ( "net/http" "slices" "strings" + + log "github.com/codeshelldev/gotl/pkg/logger" ) var IPFilter Middleware = Middleware{ @@ -28,9 +30,7 @@ func ipFilterHandler(next http.Handler) http.Handler { ip := getContext[net.IP](req, clientIPKey) - block := blockIP(ip, ipFilter) - - if block { + if blockIP(ip, ipFilter) { logger.Warn("Client IP is blocked by filter: ", ip.String()) http.Error(w, "Forbidden", http.StatusForbidden) return @@ -75,6 +75,9 @@ func blockIP(ip net.IP, ipfilter []string) (bool) { return try.Contains(ip) }) + log.Dev(allowed, blocked) + log.Dev(isExplicitlyAllowed, " ", isExplicitlyBlocked) + // explicit allow > block if isExplicitlyAllowed { return false @@ -86,11 +89,13 @@ func blockIP(ip net.IP, ipfilter []string) (bool) { // only allowed ips -> block anything not allowed if len(allowed) > 0 && len(blocked) == 0 { + log.Dev("Block all except allowed") return true } // only blocked ips -> allow anything not blocked if len(blocked) > 0 && len(allowed) == 0 { + log.Dev("Allow all except blocked") return false } From fd476357e65772f3fe0ec6948a998b0700b46237 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sat, 3 Jan 2026 23:58:05 +0100 Subject: [PATCH 12/16] remove debugs --- internals/proxy/middlewares/ipfilter.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/internals/proxy/middlewares/ipfilter.go b/internals/proxy/middlewares/ipfilter.go index 6647da55..c016387b 100644 --- a/internals/proxy/middlewares/ipfilter.go +++ b/internals/proxy/middlewares/ipfilter.go @@ -22,15 +22,13 @@ func ipFilterHandler(next http.Handler) http.Handler { ipFilter := conf.SETTINGS.ACCESS.IP_FILTER - logger.Dev(ipFilter) - if ipFilter == nil { ipFilter = getConfig("").SETTINGS.ACCESS.ENDPOINTS } ip := getContext[net.IP](req, clientIPKey) - if blockIP(ip, ipFilter) { + if isIPBlocked(ip, ipFilter) { logger.Warn("Client IP is blocked by filter: ", ip.String()) http.Error(w, "Forbidden", http.StatusForbidden) return @@ -57,8 +55,8 @@ func getIPNets(ipNets []string) ([]string, []string) { return allowedIPNets, blockedIPNets } -func blockIP(ip net.IP, ipfilter []string) (bool) { - if len(ipfilter) == 0 { +func isIPBlocked(ip net.IP, ipfilter []string) (bool) { + if len(ipfilter) == 0 || ipfilter == nil { // default: allow all return false } @@ -89,13 +87,11 @@ func blockIP(ip net.IP, ipfilter []string) (bool) { // only allowed ips -> block anything not allowed if len(allowed) > 0 && len(blocked) == 0 { - log.Dev("Block all except allowed") return true } // only blocked ips -> allow anything not blocked if len(blocked) > 0 && len(allowed) == 0 { - log.Dev("Allow all except blocked") return false } From a9f2d4fc3cb498636f054012124f12851fb48ef6 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 4 Jan 2026 00:02:15 +0100 Subject: [PATCH 13/16] . --- internals/proxy/middlewares/endpoints.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internals/proxy/middlewares/endpoints.go b/internals/proxy/middlewares/endpoints.go index bee8f6b1..507954f7 100644 --- a/internals/proxy/middlewares/endpoints.go +++ b/internals/proxy/middlewares/endpoints.go @@ -26,7 +26,7 @@ func endpointsHandler(next http.Handler) http.Handler { reqPath := req.URL.Path - if isBlocked(reqPath, endpoints) { + if isEndpointBlocked(reqPath, endpoints) { logger.Warn("Client tried to access blocked endpoint: ", reqPath) http.Error(w, "Forbidden", http.StatusForbidden) return @@ -58,8 +58,8 @@ func matchesPattern(endpoint, pattern string) bool { return ok } -func isBlocked(endpoint string, endpoints []string) bool { - if len(endpoints) == 0 { +func isEndpointBlocked(endpoint string, endpoints []string) bool { + if len(endpoints) == 0 || endpoints == nil { // default: block all return true } From 3d9596b154767a1c6dfe5c239603031f319688e9 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 6 Jan 2026 18:51:32 +0100 Subject: [PATCH 14/16] Update ipfilter.go --- internals/proxy/middlewares/ipfilter.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/internals/proxy/middlewares/ipfilter.go b/internals/proxy/middlewares/ipfilter.go index c016387b..9a87bd04 100644 --- a/internals/proxy/middlewares/ipfilter.go +++ b/internals/proxy/middlewares/ipfilter.go @@ -73,9 +73,6 @@ func isIPBlocked(ip net.IP, ipfilter []string) (bool) { return try.Contains(ip) }) - log.Dev(allowed, blocked) - log.Dev(isExplicitlyAllowed, " ", isExplicitlyBlocked) - // explicit allow > block if isExplicitlyAllowed { return false @@ -85,13 +82,13 @@ func isIPBlocked(ip net.IP, ipfilter []string) (bool) { return true } - // only allowed ips -> block anything not allowed - if len(allowed) > 0 && len(blocked) == 0 { + // if any allow rules exist, default is deny + if len(allowed) > 0 { return true } - + // only blocked ips -> allow anything not blocked - if len(blocked) > 0 && len(allowed) == 0 { + if len(blocked) > 0 { return false } From 242a250952e9f050a09701e1c346f13f86689b38 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 6 Jan 2026 19:47:59 +0100 Subject: [PATCH 15/16] . --- internals/config/tokens.go | 2 +- internals/proxy/middlewares/ipfilter.go | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/internals/config/tokens.go b/internals/config/tokens.go index c904cd80..6fb44532 100644 --- a/internals/config/tokens.go +++ b/internals/config/tokens.go @@ -66,7 +66,7 @@ func InitTokens() { ENV.INSECURE = true - // Set Blocked Endpoints on Config to Client Layer Value + // Set Blocked Endpoints on Config to User Layer Value // => effectively ignoring Default Layer DEFAULT.SETTINGS.ACCESS.ENDPOINTS = userConf.Layer.Strings("settings.access.endpoints") } diff --git a/internals/proxy/middlewares/ipfilter.go b/internals/proxy/middlewares/ipfilter.go index 9a87bd04..b4138e47 100644 --- a/internals/proxy/middlewares/ipfilter.go +++ b/internals/proxy/middlewares/ipfilter.go @@ -5,8 +5,6 @@ import ( "net/http" "slices" "strings" - - log "github.com/codeshelldev/gotl/pkg/logger" ) var IPFilter Middleware = Middleware{ From a4d9c17a09e98c97e9b365f0dcc5ba80540d867e Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Tue, 6 Jan 2026 20:18:22 +0100 Subject: [PATCH 16/16] fixed merge mistake --- internals/proxy/middlewares/endpoints.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internals/proxy/middlewares/endpoints.go b/internals/proxy/middlewares/endpoints.go index 9c8fd53d..c33e45be 100644 --- a/internals/proxy/middlewares/endpoints.go +++ b/internals/proxy/middlewares/endpoints.go @@ -58,7 +58,7 @@ func matchesPattern(endpoint, pattern string) bool { return ok } -func isBlocked(endpoint string, endpoints []string) bool { +func isEndpointBlocked(endpoint string, endpoints []string) bool { if len(endpoints) == 0 || endpoints == nil { // default: allow all return false