From 70178b511a2284b343d9efe5a367de43779580fa Mon Sep 17 00:00:00 2001
From: Someone <10882916+InterN0te@users.noreply.github.com>
Date: Wed, 9 Oct 2024 03:55:37 +0200
Subject: [PATCH 01/16] Add Trusted Proxies parameter
Missing webui management
---
client/src/pages/config/users/configman.jsx | 3 +++
src/proxy/shield.go | 5 +++--
src/utils/types.go | 1 +
src/utils/utils.go | 19 +++++++++++++++++++
4 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/client/src/pages/config/users/configman.jsx b/client/src/pages/config/users/configman.jsx
index 4b532c19..186625ff 100644
--- a/client/src/pages/config/users/configman.jsx
+++ b/client/src/pages/config/users/configman.jsx
@@ -106,6 +106,7 @@ const ConfigManagement = () => {
GenerateMissingAuthCert: config.HTTPConfig.GenerateMissingAuthCert,
HTTPPort: config.HTTPConfig.HTTPPort,
HTTPSPort: config.HTTPConfig.HTTPSPort,
+ TrustedProxies: config.TrustedProxies && config.TrustedProxies.join(', '),
SSLEmail: config.HTTPConfig.SSLEmail,
UseWildcardCertificate: config.HTTPConfig.UseWildcardCertificate,
HTTPSCertificateMode: config.HTTPConfig.HTTPSCertificateMode,
@@ -205,6 +206,8 @@ const ConfigManagement = () => {
AllowSearchEngine: values.AllowSearchEngine,
AllowHTTPLocalIPAccess: values.AllowHTTPLocalIPAccess,
PublishMDNS: values.PublishMDNS,
+ TrustedProxies: (values.TrustedProxies && values.TrustedProxies != "") ?
+ values.TrustedProxies.split(',').map((x) => x.trim()) : [],
},
EmailConfig: {
...config.EmailConfig,
diff --git a/src/proxy/shield.go b/src/proxy/shield.go
index c4bdfffa..5efaf209 100644
--- a/src/proxy/shield.go
+++ b/src/proxy/shield.go
@@ -7,6 +7,7 @@ import (
"fmt"
"math"
"strconv"
+ "strings"
"github.com/azukaar/cosmos-server/src/utils"
"github.com/azukaar/cosmos-server/src/metrics"
@@ -288,9 +289,9 @@ func GetClientID(r *http.Request, route utils.ProxyRouteConfig) string {
isConstIP := utils.IsConstellationIP(remoteAddr)
isConstTokenValid := constellation.CheckConstellationToken(r) == nil
- if (UseForwardedFor && r.Header.Get("x-forwarded-for") != "") ||
+ if ((UseForwardedFor || utils.IsTrustedProxy(remoteAddr) ) && r.Header.Get("x-forwarded-for") != "") ||
(isTunneledIp && isConstIP && isConstTokenValid) {
- ip, _ := utils.SplitIP(r.Header.Get("x-forwarded-for"))
+ ip := strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0]
utils.Debug("SmartShield: Getting forwarded client ID " + ip)
return ip
} else {
diff --git a/src/utils/types.go b/src/utils/types.go
index 7c173b47..06e062da 100644
--- a/src/utils/types.go
+++ b/src/utils/types.go
@@ -175,6 +175,7 @@ type HTTPConfig struct {
UseForwardedFor bool
AllowSearchEngine bool
PublishMDNS bool
+ TrustedProxies []string
}
const (
diff --git a/src/utils/utils.go b/src/utils/utils.go
index d77f03cf..49e876e7 100644
--- a/src/utils/utils.go
+++ b/src/utils/utils.go
@@ -891,6 +891,25 @@ func IsConstellationIP(ip string) bool {
return false
}
+func IsTrustedProxy(ip string) bool {
+ ipAddr := osnet.ParseIP(ip)
+ for _, trustedProxy := range GetMainConfig().HTTPConfig.TrustedProxies {
+ _, cidr, err := osnet.ParseCIDR(trustedProxy)
+ if err != nil {
+ // If it's not a CIDR, check for exact match
+ if ip == trustedProxy {
+ return true
+ }
+ } else {
+ // Check if the IP is in the CIDR range
+ if cidr.Contains(ipAddr) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
func SplitIP(ipPort string) (string, string) {
host, port, err := osnet.SplitHostPort(ipPort)
if err != nil {
From 03b7db34abfed37da328e507f800a20ad3ddc555 Mon Sep 17 00:00:00 2001
From: Someone <10882916+InterN0te@users.noreply.github.com>
Date: Wed, 9 Oct 2024 13:03:25 +0200
Subject: [PATCH 02/16] Add WebUI management
---
client/src/pages/config/users/configman.jsx | 13 ++++++++++++-
.../locales/en-FUNNYSHAKESPEARE/translation.json | 2 ++
client/src/utils/locales/fr/translation.json | 2 ++
3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/client/src/pages/config/users/configman.jsx b/client/src/pages/config/users/configman.jsx
index 186625ff..c7cbadf7 100644
--- a/client/src/pages/config/users/configman.jsx
+++ b/client/src/pages/config/users/configman.jsx
@@ -106,7 +106,7 @@ const ConfigManagement = () => {
GenerateMissingAuthCert: config.HTTPConfig.GenerateMissingAuthCert,
HTTPPort: config.HTTPConfig.HTTPPort,
HTTPSPort: config.HTTPConfig.HTTPSPort,
- TrustedProxies: config.TrustedProxies && config.TrustedProxies.join(', '),
+ TrustedProxies: config.HTTPConfig.TrustedProxies && config.HTTPConfig.TrustedProxies.join(', '),
SSLEmail: config.HTTPConfig.SSLEmail,
UseWildcardCertificate: config.HTTPConfig.UseWildcardCertificate,
HTTPSCertificateMode: config.HTTPConfig.HTTPSCertificateMode,
@@ -618,6 +618,17 @@ const ConfigManagement = () => {
)}
+
+
+
+
+
+
{t('mgmt.config.http.allowSearchIndexCheckbox')}
diff --git a/client/src/utils/locales/en-FUNNYSHAKESPEARE/translation.json b/client/src/utils/locales/en-FUNNYSHAKESPEARE/translation.json
index 6e8463f9..87ff024d 100644
--- a/client/src/utils/locales/en-FUNNYSHAKESPEARE/translation.json
+++ b/client/src/utils/locales/en-FUNNYSHAKESPEARE/translation.json
@@ -174,6 +174,8 @@
"mgmt.config.http.hostnameInput.HostnameLabel": "Hostname: This shall be used to restrict access to thy Cosmos Server (Thy IP, or domain name)",
"mgmt.config.http.hostnameInput.HostnameValidation": "Hostname is utterly required",
"mgmt.config.http.publishMDNSCheckbox": "This shall allow thee to publish thy server on thine local network using mDNS. So all thy .local domains will be available upon thine local network with no extra config.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "Trusted proxies allow X-Forwarded-For from an IP/IP range.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Use this setting when you have an upstream proxy server to avoid it being blocked by Shield. IP or IP range separated by commas",
"mgmt.config.email.notifyLoginCheckbox.notifyLoginLabel": "Notifyeth Users upon Successful Login",
"mgmt.config.proxy.noRoutesConfiguredText": "No routes have been configured, alas.",
"mgmt.config.proxy.originTitle": "Origin from whence thou comest",
diff --git a/client/src/utils/locales/fr/translation.json b/client/src/utils/locales/fr/translation.json
index 691859fb..d627e2d6 100644
--- a/client/src/utils/locales/fr/translation.json
+++ b/client/src/utils/locales/fr/translation.json
@@ -174,6 +174,8 @@
"mgmt.config.http.hostnameInput.HostnameLabel": "Nom d'hôte : Cela sera utilisé pour restreindre l'accès à votre serveur Cosmos (Votre IP, ou votre nom de domaine)",
"mgmt.config.http.hostnameInput.HostnameValidation": "Le nom d'hôte est obligatoire",
"mgmt.config.http.publishMDNSCheckbox": "Cela vous permet de publier votre serveur sur votre réseau local en utilisant mDNS. Cela signifie que tous vos domaines .local seront disponibles sur votre réseau local sans configuration supplémentaire.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "Proxy de confiance pour l'utilisation de l'entête X-Forwarded-For.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Utilisez ce paramètre lorsque vous avez un serveur proxy en amont pour éviter le blocage de celui-ci par le Shield. IP ou plage IP séparées par des virgules",
"mgmt.config.email.notifyLoginCheckbox.notifyLoginLabel": "Notifier les utilisateurs en cas de connexion réussie",
"mgmt.config.proxy.noRoutesConfiguredText": "Aucune route configurée.",
"mgmt.config.proxy.originTitle": "Origine",
From 345f803224210c80bce6a2f4520e38b76416203c Mon Sep 17 00:00:00 2001
From: Someone <10882916+InterN0te@users.noreply.github.com>
Date: Wed, 9 Oct 2024 13:10:19 +0200
Subject: [PATCH 03/16] Update translation.json
---
client/src/utils/locales/en/translation.json | 2 ++
1 file changed, 2 insertions(+)
diff --git a/client/src/utils/locales/en/translation.json b/client/src/utils/locales/en/translation.json
index e7329f38..606d0e6d 100644
--- a/client/src/utils/locales/en/translation.json
+++ b/client/src/utils/locales/en/translation.json
@@ -176,6 +176,8 @@
"mgmt.config.http.hostnameInput.HostnameLabel": "Hostname: This will be used to restrict access to your Cosmos Server (Your IP, or your domain name)",
"mgmt.config.http.hostnameInput.HostnameValidation": "Hostname is required",
"mgmt.config.http.publishMDNSCheckbox": "This allows you to publish your server on your local network using mDNS. This means all your .local domains will be available on your local network with no additional config.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "Trusted proxies allow X-Forwarded-For from an IP/IP range.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Use this setting when you have an upstream proxy server to avoid it being blocked by Shield. IP or IP range separated by commas",
"mgmt.config.email.notifyLoginCheckbox.notifyLoginLabel": "Notify Users upon Successful Login",
"mgmt.config.proxy.noRoutesConfiguredText": "No routes configured.",
"mgmt.config.proxy.originTitle": "Origin",
From 903434f4510555ca67a035bba6de8a9cf0b032ed Mon Sep 17 00:00:00 2001
From: Someone <10882916+InterN0te@users.noreply.github.com>
Date: Wed, 9 Oct 2024 13:12:17 +0200
Subject: [PATCH 04/16] revert en-FUNNYSHAKESPEARE
---
client/src/utils/locales/en-FUNNYSHAKESPEARE/translation.json | 2 --
1 file changed, 2 deletions(-)
diff --git a/client/src/utils/locales/en-FUNNYSHAKESPEARE/translation.json b/client/src/utils/locales/en-FUNNYSHAKESPEARE/translation.json
index 87ff024d..6e8463f9 100644
--- a/client/src/utils/locales/en-FUNNYSHAKESPEARE/translation.json
+++ b/client/src/utils/locales/en-FUNNYSHAKESPEARE/translation.json
@@ -174,8 +174,6 @@
"mgmt.config.http.hostnameInput.HostnameLabel": "Hostname: This shall be used to restrict access to thy Cosmos Server (Thy IP, or domain name)",
"mgmt.config.http.hostnameInput.HostnameValidation": "Hostname is utterly required",
"mgmt.config.http.publishMDNSCheckbox": "This shall allow thee to publish thy server on thine local network using mDNS. So all thy .local domains will be available upon thine local network with no extra config.",
- "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "Trusted proxies allow X-Forwarded-For from an IP/IP range.",
- "mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Use this setting when you have an upstream proxy server to avoid it being blocked by Shield. IP or IP range separated by commas",
"mgmt.config.email.notifyLoginCheckbox.notifyLoginLabel": "Notifyeth Users upon Successful Login",
"mgmt.config.proxy.noRoutesConfiguredText": "No routes have been configured, alas.",
"mgmt.config.proxy.originTitle": "Origin from whence thou comest",
From 7755afcebc66424a479275c8a1eca13bf8505de4 Mon Sep 17 00:00:00 2001
From: Someone <10882916+InterN0te@users.noreply.github.com>
Date: Wed, 9 Oct 2024 13:21:52 +0200
Subject: [PATCH 05/16] Edit TrustesProxiesLabel
---
client/src/utils/locales/en/translation.json | 2 +-
client/src/utils/locales/fr/translation.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/client/src/utils/locales/en/translation.json b/client/src/utils/locales/en/translation.json
index 606d0e6d..df6c58aa 100644
--- a/client/src/utils/locales/en/translation.json
+++ b/client/src/utils/locales/en/translation.json
@@ -176,7 +176,7 @@
"mgmt.config.http.hostnameInput.HostnameLabel": "Hostname: This will be used to restrict access to your Cosmos Server (Your IP, or your domain name)",
"mgmt.config.http.hostnameInput.HostnameValidation": "Hostname is required",
"mgmt.config.http.publishMDNSCheckbox": "This allows you to publish your server on your local network using mDNS. This means all your .local domains will be available on your local network with no additional config.",
- "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "Trusted proxies allow X-Forwarded-For from an IP/IP range.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "Trusted proxies allow X-Forwarded-For from IP/IP range (separated by comma).",
"mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Use this setting when you have an upstream proxy server to avoid it being blocked by Shield. IP or IP range separated by commas",
"mgmt.config.email.notifyLoginCheckbox.notifyLoginLabel": "Notify Users upon Successful Login",
"mgmt.config.proxy.noRoutesConfiguredText": "No routes configured.",
diff --git a/client/src/utils/locales/fr/translation.json b/client/src/utils/locales/fr/translation.json
index d627e2d6..9cfaaf88 100644
--- a/client/src/utils/locales/fr/translation.json
+++ b/client/src/utils/locales/fr/translation.json
@@ -174,7 +174,7 @@
"mgmt.config.http.hostnameInput.HostnameLabel": "Nom d'hôte : Cela sera utilisé pour restreindre l'accès à votre serveur Cosmos (Votre IP, ou votre nom de domaine)",
"mgmt.config.http.hostnameInput.HostnameValidation": "Le nom d'hôte est obligatoire",
"mgmt.config.http.publishMDNSCheckbox": "Cela vous permet de publier votre serveur sur votre réseau local en utilisant mDNS. Cela signifie que tous vos domaines .local seront disponibles sur votre réseau local sans configuration supplémentaire.",
- "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "Proxy de confiance pour l'utilisation de l'entête X-Forwarded-For.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "IP/Plage IP des proxys de confiance (séparé par des virgules) pour l'utilisation de X-Forwarded-For.",
"mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Utilisez ce paramètre lorsque vous avez un serveur proxy en amont pour éviter le blocage de celui-ci par le Shield. IP ou plage IP séparées par des virgules",
"mgmt.config.email.notifyLoginCheckbox.notifyLoginLabel": "Notifier les utilisateurs en cas de connexion réussie",
"mgmt.config.proxy.noRoutesConfiguredText": "Aucune route configurée.",
From 11d41ca0815fb861b0ee0aac5ebfa08d98296422 Mon Sep 17 00:00:00 2001
From: Someone <10882916+InterN0te@users.noreply.github.com>
Date: Wed, 9 Oct 2024 13:38:30 +0200
Subject: [PATCH 06/16] Fix Helpertext message
---
client/src/pages/config/users/configman.jsx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/client/src/pages/config/users/configman.jsx b/client/src/pages/config/users/configman.jsx
index c7cbadf7..be9f84d3 100644
--- a/client/src/pages/config/users/configman.jsx
+++ b/client/src/pages/config/users/configman.jsx
@@ -621,11 +621,13 @@ const ConfigManagement = () => {
+
+ {t('mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText')}
+
From 12e0dc6287604df67fde261d6f84f88c1fde82f7 Mon Sep 17 00:00:00 2001
From: Someone <10882916+InterN0te@users.noreply.github.com>
Date: Wed, 9 Oct 2024 13:38:49 +0200
Subject: [PATCH 07/16] Fix translation
---
client/src/utils/locales/en/translation.json | 4 ++--
client/src/utils/locales/fr/translation.json | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/client/src/utils/locales/en/translation.json b/client/src/utils/locales/en/translation.json
index df6c58aa..6df4da74 100644
--- a/client/src/utils/locales/en/translation.json
+++ b/client/src/utils/locales/en/translation.json
@@ -176,8 +176,8 @@
"mgmt.config.http.hostnameInput.HostnameLabel": "Hostname: This will be used to restrict access to your Cosmos Server (Your IP, or your domain name)",
"mgmt.config.http.hostnameInput.HostnameValidation": "Hostname is required",
"mgmt.config.http.publishMDNSCheckbox": "This allows you to publish your server on your local network using mDNS. This means all your .local domains will be available on your local network with no additional config.",
- "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "Trusted proxies allow X-Forwarded-For from IP/IP range (separated by comma).",
- "mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Use this setting when you have an upstream proxy server to avoid it being blocked by Shield. IP or IP range separated by commas",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "Trusted proxies allow X-Forwarded-For from IP/IP range.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Use this setting when you have an upstream proxy server to avoid it being blocked by Shield. IPs or IP ranges separated by commas.",
"mgmt.config.email.notifyLoginCheckbox.notifyLoginLabel": "Notify Users upon Successful Login",
"mgmt.config.proxy.noRoutesConfiguredText": "No routes configured.",
"mgmt.config.proxy.originTitle": "Origin",
diff --git a/client/src/utils/locales/fr/translation.json b/client/src/utils/locales/fr/translation.json
index 9cfaaf88..598063dc 100644
--- a/client/src/utils/locales/fr/translation.json
+++ b/client/src/utils/locales/fr/translation.json
@@ -174,8 +174,8 @@
"mgmt.config.http.hostnameInput.HostnameLabel": "Nom d'hôte : Cela sera utilisé pour restreindre l'accès à votre serveur Cosmos (Votre IP, ou votre nom de domaine)",
"mgmt.config.http.hostnameInput.HostnameValidation": "Le nom d'hôte est obligatoire",
"mgmt.config.http.publishMDNSCheckbox": "Cela vous permet de publier votre serveur sur votre réseau local en utilisant mDNS. Cela signifie que tous vos domaines .local seront disponibles sur votre réseau local sans configuration supplémentaire.",
- "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "IP/Plage IP des proxys de confiance (séparé par des virgules) pour l'utilisation de X-Forwarded-For.",
- "mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Utilisez ce paramètre lorsque vous avez un serveur proxy en amont pour éviter le blocage de celui-ci par le Shield. IP ou plage IP séparées par des virgules",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesLabel": "IPs/Plages IP des proxys de confiance pour l'utilisation de X-Forwarded-For.",
+ "mgmt.config.http.TrustedProxiesInput.TrustesProxiesHelperText": "Utilisez ce paramètre lorsque vous avez un serveur proxy en amont pour éviter le blocage de celui-ci par le Shield. IPs ou plages IP séparées par des virgules.",
"mgmt.config.email.notifyLoginCheckbox.notifyLoginLabel": "Notifier les utilisateurs en cas de connexion réussie",
"mgmt.config.proxy.noRoutesConfiguredText": "Aucune route configurée.",
"mgmt.config.proxy.originTitle": "Origine",
From 5c63102b4c03372595aaf853a9c428ebcecf0a6e Mon Sep 17 00:00:00 2001
From: Someone <10882916+InterN0te@users.noreply.github.com>
Date: Mon, 14 Oct 2024 18:15:18 +0200
Subject: [PATCH 08/16] Apply Real IP in BannedIPs and Blockers
Added the real client IP as ClientID in Context and used this for IP abuse count/block/ban
---
src/httpServer.go | 2 ++
src/proxy/shield.go | 2 +-
src/utils/middleware.go | 72 +++++++++++++++++++++++++----------------
src/utils/utils.go | 17 +++++++---
4 files changed, 60 insertions(+), 33 deletions(-)
diff --git a/src/httpServer.go b/src/httpServer.go
index 22d21b96..a1901ce7 100644
--- a/src/httpServer.go
+++ b/src/httpServer.go
@@ -359,6 +359,8 @@ func InitServer() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
+ router.Use(utils.ClientRealIP)
+
router.Use(utils.BlockBannedIPs)
router.Use(utils.Logger)
diff --git a/src/proxy/shield.go b/src/proxy/shield.go
index 81cb680b..1ab3489d 100644
--- a/src/proxy/shield.go
+++ b/src/proxy/shield.go
@@ -304,7 +304,7 @@ func GetClientID(r *http.Request, route utils.ProxyRouteConfig) string {
if ((UseForwardedFor || utils.IsTrustedProxy(remoteAddr) ) && r.Header.Get("x-forwarded-for") != "") ||
(isTunneledIp && isConstIP && isConstTokenValid) {
- ip := strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0]
+ ip := strings.TrimSpace(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0])
utils.Debug("SmartShield: Getting forwarded client ID " + ip)
return ip
} else {
diff --git a/src/utils/middleware.go b/src/utils/middleware.go
index 81c0c44c..ff8b8967 100644
--- a/src/utils/middleware.go
+++ b/src/utils/middleware.go
@@ -48,34 +48,51 @@ func getIPAbuseCounter(ip string) int64 {
return atomic.LoadInt64(&counter.val)
}
+func ClientRealIP(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ clientID := GetClientIP(r)
+ if(clientID == ""){
+ http.Error(w, "Invalid request", http.StatusBadRequest)
+ return
+ } else {
+ Debug("Add ClientID in context : " + clientID)
+ }
+
+ ctx := context.WithValue(r.Context(), "ClientID", clientID)
+ r = r.WithContext(ctx)
+
+ next.ServeHTTP(w, r)
+ })
+}
+
func BlockBannedIPs(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- ip, _, err := net.SplitHostPort(r.RemoteAddr)
- if err != nil {
- if hj, ok := w.(http.Hijacker); ok {
- conn, _, err := hj.Hijack()
- if err == nil {
- conn.Close()
- }
- }
- return
+ ip, ok := r.Context().Value("ClientID").(string)
+ if !ok {
+ if hj, ok := w.(http.Hijacker); ok {
+ conn, _, err := hj.Hijack()
+ if err == nil {
+ conn.Close()
+ }
+ }
+ return
}
- nbAbuse := getIPAbuseCounter(ip)
+ nbAbuse := getIPAbuseCounter(ip)
if nbAbuse > 275 {
- Warn("IP " + ip + " has " + fmt.Sprintf("%d", nbAbuse) + " abuse(s) and will soon be banned.")
- }
+ Warn("IP " + ip + " has " + fmt.Sprintf("%d", nbAbuse) + " abuse(s) and will soon be banned.")
+ }
if nbAbuse > 300 {
- if hj, ok := w.(http.Hijacker); ok {
- conn, _, err := hj.Hijack()
- if err == nil {
- conn.Close()
- }
- }
- return
+ if hj, ok := w.(http.Hijacker); ok {
+ conn, _, err := hj.Hijack()
+ if err == nil {
+ conn.Close()
}
+ }
+ return
+ }
next.ServeHTTP(w, r)
})
@@ -204,8 +221,8 @@ func GetIPLocation(ip string) (string, error) {
func BlockByCountryMiddleware(blockedCountries []string, CountryBlacklistIsWhitelist bool) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- ip, _, err := net.SplitHostPort(r.RemoteAddr)
- if err != nil {
+ ip, ok := r.Context().Value("ClientID").(string)
+ if !ok {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
@@ -287,7 +304,7 @@ func BlockPostWithoutReferer(next http.Handler) http.Handler {
Error("Blocked POST request without Referer header", nil)
http.Error(w, "Bad Request: Invalid request.", http.StatusBadRequest)
- ip, _, _ := net.SplitHostPort(r.RemoteAddr)
+ ip, _ := r.Context().Value("ClientID").(string)
if ip != "" {
TriggerEvent(
"cosmos.proxy.shield.referer",
@@ -346,7 +363,7 @@ func EnsureHostname(next http.Handler) http.Handler {
w.WriteHeader(http.StatusBadRequest)
http.Error(w, "Bad Request: Invalid hostname. Use your domain instead of your IP to access your server. Check logs if more details are needed.", http.StatusBadRequest)
- ip, _, _ := net.SplitHostPort(r.RemoteAddr)
+ ip, _ := r.Context().Value("ClientID").(string)
if ip != "" {
TriggerEvent(
"cosmos.proxy.shield.hostname",
@@ -412,7 +429,7 @@ func EnsureHostnameCosmosAPI(next http.Handler) http.Handler {
w.WriteHeader(http.StatusBadRequest)
http.Error(w, "Bad Request: Invalid hostname. Use your domain instead of your IP to access your server. Check logs if more details are needed.", http.StatusBadRequest)
- ip, _, _ := net.SplitHostPort(r.RemoteAddr)
+ ip, _ := r.Context().Value("ClientID").(string)
if ip != "" {
TriggerEvent(
"cosmos.proxy.shield.hostname",
@@ -483,8 +500,9 @@ func Restrictions(RestrictToConstellation bool, WhitelistInboundIPs []string) fu
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- ip, _, err := net.SplitHostPort(r.RemoteAddr)
- if err != nil {
+ remoteAddr, _, err := net.SplitHostPort(r.RemoteAddr)
+ ip, ok := r.Context().Value("ClientID").(string)
+ if (err != nil) || !ok {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
@@ -492,7 +510,7 @@ func Restrictions(RestrictToConstellation bool, WhitelistInboundIPs []string) fu
isUsingWhiteList := len(WhitelistInboundIPs) > 0
isInWhitelist := false
- isInConstellation := strings.HasPrefix(ip, "192.168.201.") || strings.HasPrefix(ip, "192.168.202.")
+ isInConstellation := strings.HasPrefix(remoteAddr, "192.168.201.") || strings.HasPrefix(remoteAddr, "192.168.202.")
for _, ipRange := range WhitelistInboundIPs {
Debug("Checking if " + ip + " is in " + ipRange)
diff --git a/src/utils/utils.go b/src/utils/utils.go
index 7c586d18..e1fcab59 100644
--- a/src/utils/utils.go
+++ b/src/utils/utils.go
@@ -779,11 +779,18 @@ func DownloadFile(url string) (string, error) {
}
func GetClientIP(req *http.Request) string {
- /*ip := req.Header.Get("X-Forwarded-For")
- if ip == "" {
- ip = req.RemoteAddr
- }*/
- return req.RemoteAddr
+ // when using Docker we need to get the real IP
+ remoteAddr, _ := SplitIP(req.RemoteAddr)
+ UseForwardedFor := GetMainConfig().HTTPConfig.UseForwardedFor
+
+ if ((UseForwardedFor || IsTrustedProxy(remoteAddr)) && req.Header.Get("x-forwarded-for") != "") {
+ ip := strings.TrimSpace(strings.Split(req.Header.Get("X-Forwarded-For"), ",")[0])
+ Debug("Client IP : " + ip)
+ return ip
+ } else {
+ Debug("Client IP : " + remoteAddr)
+ return remoteAddr
+ }
}
func IsDomain(domain string) bool {
From 594b5e4cda39a92093218fad020fd61c6d1d3167 Mon Sep 17 00:00:00 2001
From: Someone <7dn1yh5j@debauchez.fr>
Date: Mon, 14 Oct 2024 21:43:01 +0200
Subject: [PATCH 09/16] Removed Debug line
---
src/utils/middleware.go | 2 --
src/utils/utils.go | 2 --
2 files changed, 4 deletions(-)
diff --git a/src/utils/middleware.go b/src/utils/middleware.go
index ff8b8967..cbd80988 100644
--- a/src/utils/middleware.go
+++ b/src/utils/middleware.go
@@ -54,8 +54,6 @@ func ClientRealIP(next http.Handler) http.Handler {
if(clientID == ""){
http.Error(w, "Invalid request", http.StatusBadRequest)
return
- } else {
- Debug("Add ClientID in context : " + clientID)
}
ctx := context.WithValue(r.Context(), "ClientID", clientID)
diff --git a/src/utils/utils.go b/src/utils/utils.go
index e1fcab59..2e3ebf0d 100644
--- a/src/utils/utils.go
+++ b/src/utils/utils.go
@@ -785,10 +785,8 @@ func GetClientIP(req *http.Request) string {
if ((UseForwardedFor || IsTrustedProxy(remoteAddr)) && req.Header.Get("x-forwarded-for") != "") {
ip := strings.TrimSpace(strings.Split(req.Header.Get("X-Forwarded-For"), ",")[0])
- Debug("Client IP : " + ip)
return ip
} else {
- Debug("Client IP : " + remoteAddr)
return remoteAddr
}
}
From 6fc014b1602354955922c8df19b469b3a656100d Mon Sep 17 00:00:00 2001
From: Someone <7dn1yh5j@debauchez.fr>
Date: Tue, 15 Oct 2024 18:55:09 +0200
Subject: [PATCH 10/16] Remove duplicated code
Using IPInRange in IsTrustedProxy
SplitIP put back in shield (this is not a problem with a standard forwarded-for header)
Modified IPInRange to allow comparison of 2 valid IPs
---
src/proxy/shield.go | 21 +++++++++++++--------
src/utils/middleware.go | 13 ++++++++-----
src/utils/utils.go | 25 ++++++-------------------
3 files changed, 27 insertions(+), 32 deletions(-)
diff --git a/src/proxy/shield.go b/src/proxy/shield.go
index 1ab3489d..46494af4 100644
--- a/src/proxy/shield.go
+++ b/src/proxy/shield.go
@@ -297,14 +297,19 @@ func calculateLowestExhaustedPercentage(policy utils.SmartShieldPolicy, userCons
func GetClientID(r *http.Request, route utils.ProxyRouteConfig) string {
// when using Docker we need to get the real IP
remoteAddr, _ := utils.SplitIP(r.RemoteAddr)
- UseForwardedFor := utils.GetMainConfig().HTTPConfig.UseForwardedFor
- isTunneledIp := constellation.GetDeviceIp(route.TunnelVia) == remoteAddr
- isConstIP := utils.IsConstellationIP(remoteAddr)
- isConstTokenValid := constellation.CheckConstellationToken(r) == nil
-
- if ((UseForwardedFor || utils.IsTrustedProxy(remoteAddr) ) && r.Header.Get("x-forwarded-for") != "") ||
- (isTunneledIp && isConstIP && isConstTokenValid) {
- ip := strings.TrimSpace(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0])
+ useForwardedForHeader := false
+ if r.Header.Get("x-forwarded-for") != "" {
+ useForwardedForHeader = utils.IsTrustedProxy(remoteAddr)
+ if !useForwardedForHeader {
+ isTunneledIp := constellation.GetDeviceIp(route.TunnelVia) == remoteAddr
+ isConstIP := utils.IsConstellationIP(remoteAddr)
+ isConstTokenValid := constellation.CheckConstellationToken(r) == nil
+ useForwardedForHeader = isTunneledIp && isConstIP && isConstTokenValid
+ }
+ }
+
+ if useForwardedForHeader {
+ ip, _ := utils.SplitIP(strings.TrimSpace(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0]))
utils.Debug("SmartShield: Getting forwarded client ID " + ip)
return ip
} else {
diff --git a/src/utils/middleware.go b/src/utils/middleware.go
index cbd80988..b0b0c383 100644
--- a/src/utils/middleware.go
+++ b/src/utils/middleware.go
@@ -481,16 +481,19 @@ func IsValidHostname(hostname string) bool {
}
func IPInRange(ipStr, cidrStr string) (bool, error) {
- _, cidrNet, err := net.ParseCIDR(cidrStr)
- if err != nil {
- return false, fmt.Errorf("parse CIDR range: %w", err)
- }
-
ip := net.ParseIP(ipStr)
if ip == nil {
return false, fmt.Errorf("parse IP: invalid IP address")
}
+ _, cidrNet, err := net.ParseCIDR(cidrStr)
+ if err != nil {
+ if ipStr == cidrStr {
+ return true, nil
+ }
+ return false, fmt.Errorf("parse CIDR range: %w", err)
+ }
+
return cidrNet.Contains(ip), nil
}
diff --git a/src/utils/utils.go b/src/utils/utils.go
index 2e3ebf0d..5c83f099 100644
--- a/src/utils/utils.go
+++ b/src/utils/utils.go
@@ -781,14 +781,11 @@ func DownloadFile(url string) (string, error) {
func GetClientIP(req *http.Request) string {
// when using Docker we need to get the real IP
remoteAddr, _ := SplitIP(req.RemoteAddr)
- UseForwardedFor := GetMainConfig().HTTPConfig.UseForwardedFor
- if ((UseForwardedFor || IsTrustedProxy(remoteAddr)) && req.Header.Get("x-forwarded-for") != "") {
- ip := strings.TrimSpace(strings.Split(req.Header.Get("X-Forwarded-For"), ",")[0])
- return ip
- } else {
- return remoteAddr
+ if req.Header.Get("x-forwarded-for") != "" && IsTrustedProxy(remoteAddr) {
+ remoteAddr, _ = SplitIP(strings.TrimSpace(strings.Split(req.Header.Get("X-Forwarded-For"), ",")[0]))
}
+ return remoteAddr
}
func IsDomain(domain string) bool {
@@ -905,22 +902,12 @@ func IsConstellationIP(ip string) bool {
}
func IsTrustedProxy(ip string) bool {
- ipAddr := osnet.ParseIP(ip)
for _, trustedProxy := range GetMainConfig().HTTPConfig.TrustedProxies {
- _, cidr, err := osnet.ParseCIDR(trustedProxy)
- if err != nil {
- // If it's not a CIDR, check for exact match
- if ip == trustedProxy {
- return true
- }
- } else {
- // Check if the IP is in the CIDR range
- if cidr.Contains(ipAddr) {
- return true
- }
+ if isInRange, _ := IPInRange(ip, trustedProxy); isInRange {
+ return true
}
}
- return false
+ return false
}
func SplitIP(ipPort string) (string, string) {
From a22b849dc9d6c9b65d4fdece5d83fe2739deee83 Mon Sep 17 00:00:00 2001
From: Someone <7dn1yh5j@debauchez.fr>
Date: Tue, 15 Oct 2024 20:22:51 +0200
Subject: [PATCH 11/16] Fix indentation
---
src/utils/middleware.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/utils/middleware.go b/src/utils/middleware.go
index b0b0c383..4d404d27 100644
--- a/src/utils/middleware.go
+++ b/src/utils/middleware.go
@@ -66,7 +66,7 @@ func ClientRealIP(next http.Handler) http.Handler {
func BlockBannedIPs(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip, ok := r.Context().Value("ClientID").(string)
- if !ok {
+ if !ok {
if hj, ok := w.(http.Hijacker); ok {
conn, _, err := hj.Hijack()
if err == nil {
From de096b2e48fb285162f4454ea1b1c1d503c79f86 Mon Sep 17 00:00:00 2001
From: Someone <7dn1yh5j@debauchez.fr>
Date: Thu, 31 Oct 2024 09:52:07 +0100
Subject: [PATCH 12/16] Update middleware.go
Resolve conflict
---
src/utils/middleware.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/utils/middleware.go b/src/utils/middleware.go
index 4d404d27..b640589c 100644
--- a/src/utils/middleware.go
+++ b/src/utils/middleware.go
@@ -82,7 +82,7 @@ func BlockBannedIPs(next http.Handler) http.Handler {
Warn("IP " + ip + " has " + fmt.Sprintf("%d", nbAbuse) + " abuse(s) and will soon be banned.")
}
- if nbAbuse > 300 {
+ if nbAbuse > 300 {
if hj, ok := w.(http.Hijacker); ok {
conn, _, err := hj.Hijack()
if err == nil {
From 969363ffd0e049089cc3ace76e32c769b2c4e8a4 Mon Sep 17 00:00:00 2001
From: Someone <7dn1yh5j@debauchez.fr>
Date: Thu, 31 Oct 2024 09:55:02 +0100
Subject: [PATCH 13/16] Resolve conflict
---
src/utils/middleware.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/utils/middleware.go b/src/utils/middleware.go
index b640589c..eecd74e4 100644
--- a/src/utils/middleware.go
+++ b/src/utils/middleware.go
@@ -82,7 +82,7 @@ func BlockBannedIPs(next http.Handler) http.Handler {
Warn("IP " + ip + " has " + fmt.Sprintf("%d", nbAbuse) + " abuse(s) and will soon be banned.")
}
- if nbAbuse > 300 {
+ nbAbuse := GetIPAbuseCounter(ip)
if hj, ok := w.(http.Hijacker); ok {
conn, _, err := hj.Hijack()
if err == nil {
From c77f94770882ca085125ed7aa131f2239d59dc1d Mon Sep 17 00:00:00 2001
From: Someone <7dn1yh5j@debauchez.fr>
Date: Thu, 31 Oct 2024 09:57:22 +0100
Subject: [PATCH 14/16] Revert "Resolve conflict"
This reverts commit 969363ffd0e049089cc3ace76e32c769b2c4e8a4.
---
src/utils/middleware.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/utils/middleware.go b/src/utils/middleware.go
index eecd74e4..b640589c 100644
--- a/src/utils/middleware.go
+++ b/src/utils/middleware.go
@@ -82,7 +82,7 @@ func BlockBannedIPs(next http.Handler) http.Handler {
Warn("IP " + ip + " has " + fmt.Sprintf("%d", nbAbuse) + " abuse(s) and will soon be banned.")
}
- nbAbuse := GetIPAbuseCounter(ip)
+ if nbAbuse > 300 {
if hj, ok := w.(http.Hijacker); ok {
conn, _, err := hj.Hijack()
if err == nil {
From ba094bcea3e4b40edfb148d2b874120e5d1e0e42 Mon Sep 17 00:00:00 2001
From: Someone <7dn1yh5j@debauchez.fr>
Date: Thu, 31 Oct 2024 09:57:30 +0100
Subject: [PATCH 15/16] Revert "Update middleware.go"
This reverts commit de096b2e48fb285162f4454ea1b1c1d503c79f86.
---
src/utils/middleware.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/utils/middleware.go b/src/utils/middleware.go
index b640589c..4d404d27 100644
--- a/src/utils/middleware.go
+++ b/src/utils/middleware.go
@@ -82,7 +82,7 @@ func BlockBannedIPs(next http.Handler) http.Handler {
Warn("IP " + ip + " has " + fmt.Sprintf("%d", nbAbuse) + " abuse(s) and will soon be banned.")
}
- if nbAbuse > 300 {
+ if nbAbuse > 300 {
if hj, ok := w.(http.Hijacker); ok {
conn, _, err := hj.Hijack()
if err == nil {
From a716e0cec838aa709b55498b765dd460c1247dda Mon Sep 17 00:00:00 2001
From: Someone <7dn1yh5j@debauchez.fr>
Date: Thu, 31 Oct 2024 09:58:11 +0100
Subject: [PATCH 16/16] Resolv conflict
---
src/utils/middleware.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/utils/middleware.go b/src/utils/middleware.go
index 4d404d27..d1a88dc3 100644
--- a/src/utils/middleware.go
+++ b/src/utils/middleware.go
@@ -76,7 +76,7 @@ func BlockBannedIPs(next http.Handler) http.Handler {
return
}
- nbAbuse := getIPAbuseCounter(ip)
+ nbAbuse := getIPAbuseCounter(ip)
if nbAbuse > 275 {
Warn("IP " + ip + " has " + fmt.Sprintf("%d", nbAbuse) + " abuse(s) and will soon be banned.")