Added support for more advanced proxy configuration
Signed-off-by: arzumify <jliwin98@danwin1210.de>
This commit is contained in:
parent
13d00e8222
commit
eebe3763f5
|
@ -88,10 +88,16 @@ routes: [
|
||||||
url: "http://localhost:8000",
|
url: "http://localhost:8000",
|
||||||
# stripPrefix defines whether to strip the prefix from the path before proxying.
|
# stripPrefix defines whether to strip the prefix from the path before proxying.
|
||||||
stripPrefix: true
|
stripPrefix: true
|
||||||
# TODO: In a future update, passing X-Forwarded-For and X-Forwarded-Proto headers will be supported.
|
headers: {
|
||||||
# TODO: In a future update, forbidding certain headers from being passed will be supported.
|
# forbid defines the headers to forbid from being sent to the proxied server.
|
||||||
# TODO: In a future update, passing X-Powered-By and Server headers will be supported.
|
forbid: ["Authorization"],
|
||||||
# TODO: In a future update, passing Host header will be supported.
|
# preserve defines the headers to preserve when sending to the client.
|
||||||
|
preserve: [X-Powered-By", "Server"]
|
||||||
|
# host defines whether the host / :authority header should be sent to the proxied server.
|
||||||
|
host: true,
|
||||||
|
# xForward defines whether to send the X-Forwarded-For and X-Forwarded-Proto headers.
|
||||||
|
xForward: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
# path defines the path to match. They can contain wildcards.
|
# path defines the path to match. They can contain wildcards.
|
||||||
|
|
81
main.go
81
main.go
|
@ -2,6 +2,8 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
library "git.ailur.dev/ailur/fg-library/v2"
|
library "git.ailur.dev/ailur/fg-library/v2"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
@ -18,8 +20,6 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
|
||||||
"net/url"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
|
@ -79,6 +79,7 @@ type Config struct {
|
||||||
Proxy struct {
|
Proxy struct {
|
||||||
URL string `yaml:"url" validate:"required"`
|
URL string `yaml:"url" validate:"required"`
|
||||||
StripPrefix bool `yaml:"stripPrefix"`
|
StripPrefix bool `yaml:"stripPrefix"`
|
||||||
|
Headers HeaderSettings `yaml:"headers"`
|
||||||
} `yaml:"proxy" validate:"required_without=Static Redirect"`
|
} `yaml:"proxy" validate:"required_without=Static Redirect"`
|
||||||
Static struct {
|
Static struct {
|
||||||
Root string `yaml:"root" validate:"required,isDirectory"`
|
Root string `yaml:"root" validate:"required,isDirectory"`
|
||||||
|
@ -101,6 +102,15 @@ type Config struct {
|
||||||
Services map[string]interface{} `yaml:"services"`
|
Services map[string]interface{} `yaml:"services"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HeaderSettings struct {
|
||||||
|
Forbid []string `yaml:"forbid"`
|
||||||
|
PreserveServer bool `yaml:"preserveServer"`
|
||||||
|
PreserveXPoweredBy bool `yaml:"preserveXPoweredBy"`
|
||||||
|
PreserveAltSvc bool `yaml:"preserveAltSvc"`
|
||||||
|
PassHost bool `yaml:"passHost"`
|
||||||
|
XForward bool `yaml:"xForward"`
|
||||||
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
ServiceID uuid.UUID
|
ServiceID uuid.UUID
|
||||||
ServiceMetadata library.Service
|
ServiceMetadata library.Service
|
||||||
|
@ -174,9 +184,15 @@ func logger(next http.Handler) http.Handler {
|
||||||
func serverChanger(next http.Handler) http.Handler {
|
func serverChanger(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if !config.Global.Stealth.Enabled {
|
if !config.Global.Stealth.Enabled {
|
||||||
|
if !strings.Contains("Server", w.Header().Get(":X-Preserve-Headers")) {
|
||||||
w.Header().Set("Server", "Fulgens HTTP Server")
|
w.Header().Set("Server", "Fulgens HTTP Server")
|
||||||
|
}
|
||||||
|
if !strings.Contains("X-Powered-By", w.Header().Get(":X-Preserve-Headers")) {
|
||||||
w.Header().Set("X-Powered-By", "Go net/http")
|
w.Header().Set("X-Powered-By", "Go net/http")
|
||||||
w.Header().Set("Alt-Svc", "Alt-Svc: h2=\":443\"; ma=3600")
|
}
|
||||||
|
if !strings.Contains("Alt-Svc", w.Header().Get(":X-Preserve-Headers")) {
|
||||||
|
w.Header().Set("Alt-Svc", "h2=\":443\"; ma=3600")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switch config.Global.Stealth.Server {
|
switch config.Global.Stealth.Server {
|
||||||
case "nginx":
|
case "nginx":
|
||||||
|
@ -196,8 +212,10 @@ func serverChanger(next http.Handler) http.Handler {
|
||||||
poweredBy.WriteString("ASP.NET")
|
poweredBy.WriteString("ASP.NET")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if poweredBy.Len() > 0 {
|
||||||
w.Header().Set("X-Powered-By", poweredBy.String())
|
w.Header().Set("X-Powered-By", poweredBy.String())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -377,6 +395,54 @@ func newFileServer(root string, directoryListing bool, path string) http.Handler
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newReverseProxy(uri *url.URL, headerSettings HeaderSettings) http.Handler {
|
||||||
|
proxy := httputil.NewSingleHostReverseProxy(uri)
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Strip the headers
|
||||||
|
for _, header := range headerSettings.Forbid {
|
||||||
|
r.Header.Del(header)
|
||||||
|
}
|
||||||
|
if !headerSettings.PassHost {
|
||||||
|
r.Host = uri.Host
|
||||||
|
}
|
||||||
|
if !headerSettings.XForward {
|
||||||
|
r.Header["X-Forwarded-For"] = nil
|
||||||
|
} else {
|
||||||
|
r.Header.Set("X-Forwarded-Host", r.Host)
|
||||||
|
if r.URL.Scheme != "" {
|
||||||
|
r.Header.Set("X-Forwarded-Proto", r.URL.Scheme)
|
||||||
|
} else {
|
||||||
|
r.Header.Set("X-Forwarded-Proto", "http")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the preserve headers which will be stripped by the server changer
|
||||||
|
var xPreserveHeaders strings.Builder
|
||||||
|
|
||||||
|
if headerSettings.PreserveServer {
|
||||||
|
xPreserveHeaders.WriteString("Server")
|
||||||
|
}
|
||||||
|
|
||||||
|
if headerSettings.PreserveXPoweredBy {
|
||||||
|
if xPreserveHeaders.Len() > 0 {
|
||||||
|
xPreserveHeaders.WriteString(", ")
|
||||||
|
}
|
||||||
|
xPreserveHeaders.WriteString("X-Powered-By")
|
||||||
|
}
|
||||||
|
|
||||||
|
if headerSettings.PreserveAltSvc {
|
||||||
|
if xPreserveHeaders.Len() > 0 {
|
||||||
|
xPreserveHeaders.WriteString(", ")
|
||||||
|
}
|
||||||
|
xPreserveHeaders.WriteString("Alt-Svc")
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set(":X-Preserve-Headers", xPreserveHeaders.String())
|
||||||
|
|
||||||
|
proxy.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func serverError(w http.ResponseWriter, status int) {
|
func serverError(w http.ResponseWriter, status int) {
|
||||||
w.Header().Set("Content-Type", "text/html")
|
w.Header().Set("Content-Type", "text/html")
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
|
@ -897,17 +963,16 @@ func iterateThroughSubdomains(globalOutbox chan library.InterServiceMessage) {
|
||||||
subdomainRouter.Handle(path, http.StripPrefix(rawPath, newFileServer(pathBlock.Static.Root, pathBlock.Static.DirectoryListing, rawPath)))
|
subdomainRouter.Handle(path, http.StripPrefix(rawPath, newFileServer(pathBlock.Static.Root, pathBlock.Static.DirectoryListing, rawPath)))
|
||||||
slog.Info("Serving static directory " + pathBlock.Static.Root + " on subdomain " + route.Subdomain + " with pattern " + path)
|
slog.Info("Serving static directory " + pathBlock.Static.Root + " on subdomain " + route.Subdomain + " with pattern " + path)
|
||||||
} else if pathBlock.Proxy.URL != "" {
|
} else if pathBlock.Proxy.URL != "" {
|
||||||
// Parse the URL
|
// Create the proxy
|
||||||
proxyUrl, err := url.Parse(pathBlock.Proxy.URL)
|
parsedURL, err := url.Parse(pathBlock.Proxy.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Error parsing URL: " + err.Error())
|
slog.Error("Error parsing URL: " + err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
// Create the proxy
|
|
||||||
if pathBlock.Proxy.StripPrefix {
|
if pathBlock.Proxy.StripPrefix {
|
||||||
subdomainRouter.Handle(path, http.StripPrefix(strings.TrimSuffix(path, "*"), httputil.NewSingleHostReverseProxy(proxyUrl)))
|
subdomainRouter.Handle(path, http.StripPrefix(strings.TrimSuffix(path, "*"), newReverseProxy(parsedURL, pathBlock.Proxy.Headers)))
|
||||||
} else {
|
} else {
|
||||||
subdomainRouter.Handle(path, httputil.NewSingleHostReverseProxy(proxyUrl))
|
subdomainRouter.Handle(path, newReverseProxy(parsedURL, pathBlock.Proxy.Headers))
|
||||||
}
|
}
|
||||||
} else if pathBlock.Redirect.URL != "" {
|
} else if pathBlock.Redirect.URL != "" {
|
||||||
// Set the code
|
// Set the code
|
||||||
|
|
Loading…
Reference in New Issue