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",
|
||||
# stripPrefix defines whether to strip the prefix from the path before proxying.
|
||||
stripPrefix: true
|
||||
# TODO: In a future update, passing X-Forwarded-For and X-Forwarded-Proto headers will be supported.
|
||||
# TODO: In a future update, forbidding certain headers from being passed will be supported.
|
||||
# TODO: In a future update, passing X-Powered-By and Server headers will be supported.
|
||||
# TODO: In a future update, passing Host header will be supported.
|
||||
headers: {
|
||||
# forbid defines the headers to forbid from being sent to the proxied server.
|
||||
forbid: ["Authorization"],
|
||||
# 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.
|
||||
|
|
81
main.go
81
main.go
|
@ -2,6 +2,8 @@ package main
|
|||
|
||||
import (
|
||||
library "git.ailur.dev/ailur/fg-library/v2"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"errors"
|
||||
"io"
|
||||
|
@ -18,8 +20,6 @@ import (
|
|||
"database/sql"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
@ -79,6 +79,7 @@ type Config struct {
|
|||
Proxy struct {
|
||||
URL string `yaml:"url" validate:"required"`
|
||||
StripPrefix bool `yaml:"stripPrefix"`
|
||||
Headers HeaderSettings `yaml:"headers"`
|
||||
} `yaml:"proxy" validate:"required_without=Static Redirect"`
|
||||
Static struct {
|
||||
Root string `yaml:"root" validate:"required,isDirectory"`
|
||||
|
@ -101,6 +102,15 @@ type Config struct {
|
|||
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 {
|
||||
ServiceID uuid.UUID
|
||||
ServiceMetadata library.Service
|
||||
|
@ -174,9 +184,15 @@ func logger(next http.Handler) http.Handler {
|
|||
func serverChanger(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !config.Global.Stealth.Enabled {
|
||||
if !strings.Contains("Server", w.Header().Get(":X-Preserve-Headers")) {
|
||||
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("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 {
|
||||
switch config.Global.Stealth.Server {
|
||||
case "nginx":
|
||||
|
@ -196,8 +212,10 @@ func serverChanger(next http.Handler) http.Handler {
|
|||
poweredBy.WriteString("ASP.NET")
|
||||
}
|
||||
|
||||
if poweredBy.Len() > 0 {
|
||||
w.Header().Set("X-Powered-By", poweredBy.String())
|
||||
}
|
||||
}
|
||||
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) {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
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)))
|
||||
slog.Info("Serving static directory " + pathBlock.Static.Root + " on subdomain " + route.Subdomain + " with pattern " + path)
|
||||
} else if pathBlock.Proxy.URL != "" {
|
||||
// Parse the URL
|
||||
proxyUrl, err := url.Parse(pathBlock.Proxy.URL)
|
||||
// Create the proxy
|
||||
parsedURL, err := url.Parse(pathBlock.Proxy.URL)
|
||||
if err != nil {
|
||||
slog.Error("Error parsing URL: " + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
// Create the proxy
|
||||
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 {
|
||||
subdomainRouter.Handle(path, httputil.NewSingleHostReverseProxy(proxyUrl))
|
||||
subdomainRouter.Handle(path, newReverseProxy(parsedURL, pathBlock.Proxy.Headers))
|
||||
}
|
||||
} else if pathBlock.Redirect.URL != "" {
|
||||
// Set the code
|
||||
|
|
Loading…
Reference in New Issue