mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-06 15:47:19 +02:00
System arch optimization
- Optimized types and definitions - Moved shutdown seq to start.go file - Moved authelia to auth/sso module - Added different auth types support (wip) - Updated proxy config structure - Added v3.1.4 to v3.1.5 auto upgrade utilities - Fixed #426 - Optimized status page UI - Added options to disable uptime montior in config
This commit is contained in:
parent
9e95d84627
commit
bb0f55018c
@ -59,7 +59,7 @@ func LoadReverseProxyConfig(configFilepath string) error {
|
|||||||
thisConfigEndpoint.RootOrMatchingDomain = "/"
|
thisConfigEndpoint.RootOrMatchingDomain = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
if thisConfigEndpoint.ProxyType == dynamicproxy.ProxyType_Root {
|
if thisConfigEndpoint.ProxyType == dynamicproxy.ProxyTypeRoot {
|
||||||
//This is a root config file
|
//This is a root config file
|
||||||
rootProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisConfigEndpoint)
|
rootProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisConfigEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -68,7 +68,7 @@ func LoadReverseProxyConfig(configFilepath string) error {
|
|||||||
|
|
||||||
dynamicProxyRouter.SetProxyRouteAsRoot(rootProxyEndpoint)
|
dynamicProxyRouter.SetProxyRouteAsRoot(rootProxyEndpoint)
|
||||||
|
|
||||||
} else if thisConfigEndpoint.ProxyType == dynamicproxy.ProxyType_Host {
|
} else if thisConfigEndpoint.ProxyType == dynamicproxy.ProxyTypeHost {
|
||||||
//This is a host config file
|
//This is a host config file
|
||||||
readyProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisConfigEndpoint)
|
readyProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisConfigEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -97,7 +97,7 @@ func filterProxyConfigFilename(filename string) string {
|
|||||||
func SaveReverseProxyConfig(endpoint *dynamicproxy.ProxyEndpoint) error {
|
func SaveReverseProxyConfig(endpoint *dynamicproxy.ProxyEndpoint) error {
|
||||||
//Get filename for saving
|
//Get filename for saving
|
||||||
filename := filepath.Join("./conf/proxy/", endpoint.RootOrMatchingDomain+".config")
|
filename := filepath.Join("./conf/proxy/", endpoint.RootOrMatchingDomain+".config")
|
||||||
if endpoint.ProxyType == dynamicproxy.ProxyType_Root {
|
if endpoint.ProxyType == dynamicproxy.ProxyTypeRoot {
|
||||||
filename = "./conf/proxy/root.config"
|
filename = "./conf/proxy/root.config"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,9 +129,15 @@ func RemoveReverseProxyConfig(endpoint string) error {
|
|||||||
// Get the default root config that point to the internal static web server
|
// Get the default root config that point to the internal static web server
|
||||||
// this will be used if root config is not found (new deployment / missing root.config file)
|
// this will be used if root config is not found (new deployment / missing root.config file)
|
||||||
func GetDefaultRootConfig() (*dynamicproxy.ProxyEndpoint, error) {
|
func GetDefaultRootConfig() (*dynamicproxy.ProxyEndpoint, error) {
|
||||||
|
//Default Authentication Provider
|
||||||
|
defaultAuth := &dynamicproxy.AuthenticationProvider{
|
||||||
|
AuthMethod: dynamicproxy.AuthMethodNone,
|
||||||
|
BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{},
|
||||||
|
BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
|
||||||
|
}
|
||||||
//Default settings
|
//Default settings
|
||||||
rootProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&dynamicproxy.ProxyEndpoint{
|
rootProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&dynamicproxy.ProxyEndpoint{
|
||||||
ProxyType: dynamicproxy.ProxyType_Root,
|
ProxyType: dynamicproxy.ProxyTypeRoot,
|
||||||
RootOrMatchingDomain: "/",
|
RootOrMatchingDomain: "/",
|
||||||
ActiveOrigins: []*loadbalance.Upstream{
|
ActiveOrigins: []*loadbalance.Upstream{
|
||||||
{
|
{
|
||||||
@ -144,9 +150,7 @@ func GetDefaultRootConfig() (*dynamicproxy.ProxyEndpoint, error) {
|
|||||||
InactiveOrigins: []*loadbalance.Upstream{},
|
InactiveOrigins: []*loadbalance.Upstream{},
|
||||||
BypassGlobalTLS: false,
|
BypassGlobalTLS: false,
|
||||||
VirtualDirectories: []*dynamicproxy.VirtualDirectoryEndpoint{},
|
VirtualDirectories: []*dynamicproxy.VirtualDirectoryEndpoint{},
|
||||||
RequireBasicAuth: false,
|
AuthenticationProvider: defaultAuth,
|
||||||
BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{},
|
|
||||||
BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
|
|
||||||
DefaultSiteOption: dynamicproxy.DefaultSite_InternalStaticWebServer,
|
DefaultSiteOption: dynamicproxy.DefaultSite_InternalStaticWebServer,
|
||||||
DefaultSiteValue: "",
|
DefaultSiteValue: "",
|
||||||
})
|
})
|
||||||
|
@ -43,7 +43,7 @@ const (
|
|||||||
/* Build Constants */
|
/* Build Constants */
|
||||||
SYSTEM_NAME = "Zoraxy"
|
SYSTEM_NAME = "Zoraxy"
|
||||||
SYSTEM_VERSION = "3.1.5"
|
SYSTEM_VERSION = "3.1.5"
|
||||||
DEVELOPMENT_BUILD = true /* Development: Set to false to use embedded web fs */
|
DEVELOPMENT_BUILD = false /* Development: Set to false to use embedded web fs */
|
||||||
|
|
||||||
/* System Constants */
|
/* System Constants */
|
||||||
DATABASE_PATH = "sys.db"
|
DATABASE_PATH = "sys.db"
|
||||||
|
43
src/main.go
43
src/main.go
@ -57,47 +57,6 @@ func SetupCloseHandler() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShutdownSeq() {
|
|
||||||
SystemWideLogger.Println("Shutting down " + SYSTEM_NAME)
|
|
||||||
SystemWideLogger.Println("Closing Netstats Listener")
|
|
||||||
if netstatBuffers != nil {
|
|
||||||
netstatBuffers.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemWideLogger.Println("Closing Statistic Collector")
|
|
||||||
if statisticCollector != nil {
|
|
||||||
statisticCollector.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
if mdnsTickerStop != nil {
|
|
||||||
SystemWideLogger.Println("Stopping mDNS Discoverer (might take a few minutes)")
|
|
||||||
// Stop the mdns service
|
|
||||||
mdnsTickerStop <- true
|
|
||||||
}
|
|
||||||
if mdnsScanner != nil {
|
|
||||||
mdnsScanner.Close()
|
|
||||||
}
|
|
||||||
SystemWideLogger.Println("Shutting down load balancer")
|
|
||||||
if loadBalancer != nil {
|
|
||||||
loadBalancer.Close()
|
|
||||||
}
|
|
||||||
SystemWideLogger.Println("Closing Certificates Auto Renewer")
|
|
||||||
if acmeAutoRenewer != nil {
|
|
||||||
acmeAutoRenewer.Close()
|
|
||||||
}
|
|
||||||
//Remove the tmp folder
|
|
||||||
SystemWideLogger.Println("Cleaning up tmp files")
|
|
||||||
os.RemoveAll("./tmp")
|
|
||||||
|
|
||||||
//Close database
|
|
||||||
SystemWideLogger.Println("Stopping system database")
|
|
||||||
sysdb.Close()
|
|
||||||
|
|
||||||
//Close logger
|
|
||||||
SystemWideLogger.Println("Closing system wide logger")
|
|
||||||
SystemWideLogger.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//Parse startup flags
|
//Parse startup flags
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
@ -141,7 +100,7 @@ func main() {
|
|||||||
csrf.SameSite(csrf.SameSiteLaxMode),
|
csrf.SameSite(csrf.SameSiteLaxMode),
|
||||||
)
|
)
|
||||||
|
|
||||||
//Startup all modules
|
//Startup all modules, see start.go
|
||||||
startupSequence()
|
startupSequence()
|
||||||
|
|
||||||
//Initiate management interface APIs
|
//Initiate management interface APIs
|
||||||
|
87
src/mod/auth/sso/authelia/authelia.go
Normal file
87
src/mod/auth/sso/authelia/authelia.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package authelia
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy"
|
||||||
|
"imuslab.com/zoraxy/mod/info/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
AutheliaURL string //URL of the Authelia server, e.g. authelia.example.com
|
||||||
|
UseHTTPS bool //Whether to use HTTPS for the Authelia server
|
||||||
|
Logger logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type AutheliaHandler struct {
|
||||||
|
options *Options
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAutheliaAuthenticator(options *Options) *AutheliaHandler {
|
||||||
|
return &AutheliaHandler{
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleAutheliaAuthRouting is the handler for Authelia authentication, if the error is not nil, the request will be forwarded to the endpoint
|
||||||
|
// Do not continue processing or write to the response writer if the error is not nil
|
||||||
|
func (h *AutheliaHandler) HandleAutheliaAuthRouting(w http.ResponseWriter, r *http.Request, pe *dynamicproxy.ProxyEndpoint) error {
|
||||||
|
err := h.handleAutheliaAuth(w, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *AutheliaHandler) handleAutheliaAuth(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
protocol := "http"
|
||||||
|
if h.options.UseHTTPS {
|
||||||
|
protocol = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
autheliaBaseURL := protocol + "://" + h.options.AutheliaURL
|
||||||
|
//Remove tailing slash if any
|
||||||
|
if autheliaBaseURL[len(autheliaBaseURL)-1] == '/' {
|
||||||
|
autheliaBaseURL = autheliaBaseURL[:len(autheliaBaseURL)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
//Make a request to Authelia to verify the request
|
||||||
|
req, err := http.NewRequest("POST", autheliaBaseURL+"/api/verify", nil)
|
||||||
|
if err != nil {
|
||||||
|
h.options.Logger.PrintAndLog("Authelia", "Unable to create request", err)
|
||||||
|
w.WriteHeader(401)
|
||||||
|
return errors.New("unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
scheme := "http"
|
||||||
|
if r.TLS != nil {
|
||||||
|
scheme = "https"
|
||||||
|
}
|
||||||
|
req.Header.Add("X-Original-URL", fmt.Sprintf("%s://%s", scheme, r.Host))
|
||||||
|
|
||||||
|
// Copy cookies from the incoming request
|
||||||
|
for _, cookie := range r.Cookies() {
|
||||||
|
req.AddCookie(cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Making the verification request
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
h.options.Logger.PrintAndLog("Authelia", "Unable to verify", err)
|
||||||
|
w.WriteHeader(401)
|
||||||
|
return errors.New("unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
redirectURL := autheliaBaseURL + "/?rd=" + url.QueryEscape(scheme+"://"+r.Host+r.URL.String()) + "&rm=" + r.Method
|
||||||
|
http.Redirect(w, r, redirectURL, http.StatusSeeOther)
|
||||||
|
return errors.New("unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -41,8 +41,8 @@ func NewDB(path string) (*DB, error) {
|
|||||||
batch: leveldb.Batch{},
|
batch: leveldb.Batch{},
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create a ticker to flush data into disk every 5 seconds
|
//Create a ticker to flush data into disk every 1 seconds
|
||||||
writeFlushTicker := time.NewTicker(5 * time.Second)
|
writeFlushTicker := time.NewTicker(1 * time.Second)
|
||||||
writeFlushStop := make(chan bool)
|
writeFlushStop := make(chan bool)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -84,16 +84,18 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//SSO Interception Mode
|
//SSO Interception Mode
|
||||||
if sep.UseSSOIntercept {
|
/*
|
||||||
|
if sep.AuthenticationProvider.SSOInterceptMode {
|
||||||
allowPass := h.Parent.Option.SSOHandler.ServeForwardAuth(w, r)
|
allowPass := h.Parent.Option.SSOHandler.ServeForwardAuth(w, r)
|
||||||
if !allowPass {
|
if !allowPass {
|
||||||
h.Parent.Option.Logger.LogHTTPRequest(r, "sso-x", 307)
|
h.Parent.Option.Logger.LogHTTPRequest(r, "sso-x", 307)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//Validate basic auth
|
//Validate basic auth
|
||||||
if sep.RequireBasicAuth {
|
if sep.AuthenticationProvider.AuthMethod == AuthMethodBasic {
|
||||||
err := h.handleBasicAuthRouting(w, r, sep)
|
err := h.handleBasicAuthRouting(w, r, sep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.Parent.Option.Logger.LogHTTPRequest(r, "host", 401)
|
h.Parent.Option.Logger.LogHTTPRequest(r, "host", 401)
|
||||||
@ -108,7 +110,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
//Virtual directory routing rule found. Route via vdir mode
|
//Virtual directory routing rule found. Route via vdir mode
|
||||||
h.vdirRequest(w, r, targetProxyEndpoint)
|
h.vdirRequest(w, r, targetProxyEndpoint)
|
||||||
return
|
return
|
||||||
} else if !strings.HasSuffix(proxyingPath, "/") && sep.ProxyType != ProxyType_Root {
|
} else if !strings.HasSuffix(proxyingPath, "/") && sep.ProxyType != ProxyTypeRoot {
|
||||||
potentialProxtEndpoint := sep.GetVirtualDirectoryHandlerFromRequestURI(proxyingPath + "/")
|
potentialProxtEndpoint := sep.GetVirtualDirectoryHandlerFromRequestURI(proxyingPath + "/")
|
||||||
if potentialProxtEndpoint != nil && !potentialProxtEndpoint.Disabled {
|
if potentialProxtEndpoint != nil && !potentialProxtEndpoint.Disabled {
|
||||||
//Missing tailing slash. Redirect to target proxy endpoint
|
//Missing tailing slash. Redirect to target proxy endpoint
|
||||||
@ -180,7 +182,7 @@ func (h *ProxyHandler) handleRootRouting(w http.ResponseWriter, r *http.Request)
|
|||||||
//Virtual directory routing rule found. Route via vdir mode
|
//Virtual directory routing rule found. Route via vdir mode
|
||||||
h.vdirRequest(w, r, targetProxyEndpoint)
|
h.vdirRequest(w, r, targetProxyEndpoint)
|
||||||
return
|
return
|
||||||
} else if !strings.HasSuffix(proxyingPath, "/") && proot.ProxyType != ProxyType_Root {
|
} else if !strings.HasSuffix(proxyingPath, "/") && proot.ProxyType != ProxyTypeRoot {
|
||||||
potentialProxtEndpoint := proot.GetVirtualDirectoryHandlerFromRequestURI(proxyingPath + "/")
|
potentialProxtEndpoint := proot.GetVirtualDirectoryHandlerFromRequestURI(proxyingPath + "/")
|
||||||
if potentialProxtEndpoint != nil && !targetProxyEndpoint.Disabled {
|
if potentialProxtEndpoint != nil && !targetProxyEndpoint.Disabled {
|
||||||
//Missing tailing slash. Redirect to target proxy endpoint
|
//Missing tailing slash. Redirect to target proxy endpoint
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
package dynamicproxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (h *ProxyHandler) handleAutheliaAuthRouting(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
|
|
||||||
err := handleAutheliaAuth(w, r, pe)
|
|
||||||
if err != nil {
|
|
||||||
h.Parent.logRequest(r, false, 401, "host", r.URL.Hostname())
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleAutheliaAuth(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
|
|
||||||
|
|
||||||
client := &http.Client{}
|
|
||||||
|
|
||||||
// TODO: provide authelia url by config variable
|
|
||||||
req, err := http.NewRequest("POST", "https://authelia.mydomain.com/api/verify", nil)
|
|
||||||
if err != nil {
|
|
||||||
pe.parent.Option.Logger.PrintAndLog("Authelia", "Unable to create request", err)
|
|
||||||
w.WriteHeader(401)
|
|
||||||
return errors.New("unauthorized")
|
|
||||||
}
|
|
||||||
|
|
||||||
scheme := "http"
|
|
||||||
if r.TLS != nil {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
req.Header.Add("X-Original-URL", fmt.Sprintf("%s://%s", scheme, r.Host))
|
|
||||||
|
|
||||||
// Copy cookies from the incoming request
|
|
||||||
for _, cookie := range r.Cookies() {
|
|
||||||
req.AddCookie(cookie)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
pe.parent.Option.Logger.PrintAndLog("Authelia", "Unable to verify", err)
|
|
||||||
w.WriteHeader(401)
|
|
||||||
return errors.New("unauthorized")
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
// TODO: provide authelia url by config variable
|
|
||||||
redirectURL := "https://authelia.mydomain.com/?rd=" + url.QueryEscape(scheme+"://"+r.Host+r.URL.String()) + "&rm=" + r.Method
|
|
||||||
|
|
||||||
http.Redirect(w, r, redirectURL, http.StatusSeeOther)
|
|
||||||
return errors.New("unauthorized")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -26,9 +26,9 @@ func (h *ProxyHandler) handleBasicAuthRouting(w http.ResponseWriter, r *http.Req
|
|||||||
// Handle basic auth logic
|
// Handle basic auth logic
|
||||||
// do not write to http.ResponseWriter if err return is not nil (already handled by this function)
|
// do not write to http.ResponseWriter if err return is not nil (already handled by this function)
|
||||||
func handleBasicAuth(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
|
func handleBasicAuth(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
|
||||||
if len(pe.BasicAuthExceptionRules) > 0 {
|
if len(pe.AuthenticationProvider.BasicAuthExceptionRules) > 0 {
|
||||||
//Check if the current path matches the exception rules
|
//Check if the current path matches the exception rules
|
||||||
for _, exceptionRule := range pe.BasicAuthExceptionRules {
|
for _, exceptionRule := range pe.AuthenticationProvider.BasicAuthExceptionRules {
|
||||||
if strings.HasPrefix(r.RequestURI, exceptionRule.PathPrefix) {
|
if strings.HasPrefix(r.RequestURI, exceptionRule.PathPrefix) {
|
||||||
//This path is excluded from basic auth
|
//This path is excluded from basic auth
|
||||||
return nil
|
return nil
|
||||||
@ -46,7 +46,7 @@ func handleBasicAuth(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint)
|
|||||||
//Check for the credentials to see if there is one matching
|
//Check for the credentials to see if there is one matching
|
||||||
hashedPassword := auth.Hash(p)
|
hashedPassword := auth.Hash(p)
|
||||||
matchingFound := false
|
matchingFound := false
|
||||||
for _, cred := range pe.BasicAuthCredentials {
|
for _, cred := range pe.AuthenticationProvider.BasicAuthCredentials {
|
||||||
if u == cred.Username && hashedPassword == cred.PasswordHash {
|
if u == cred.Username && hashedPassword == cred.PasswordHash {
|
||||||
matchingFound = true
|
matchingFound = true
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ func (router *Router) StartProxyService() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Validate basic auth
|
//Validate basic auth
|
||||||
if sep.RequireBasicAuth {
|
if sep.AuthenticationProvider.AuthMethod == AuthMethodBasic {
|
||||||
err := handleBasicAuth(w, r, sep)
|
err := handleBasicAuth(w, r, sep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -161,8 +161,8 @@ func (router *Router) StartProxyService() error {
|
|||||||
ProxyDomain: selectedUpstream.OriginIpOrDomain,
|
ProxyDomain: selectedUpstream.OriginIpOrDomain,
|
||||||
OriginalHost: originalHostHeader,
|
OriginalHost: originalHostHeader,
|
||||||
UseTLS: selectedUpstream.RequireTLS,
|
UseTLS: selectedUpstream.RequireTLS,
|
||||||
HostHeaderOverwrite: sep.RequestHostOverwrite,
|
HostHeaderOverwrite: sep.HeaderRewriteRules.RequestHostOverwrite,
|
||||||
NoRemoveHopByHop: sep.DisableHopByHopHeaderRemoval,
|
NoRemoveHopByHop: sep.HeaderRewriteRules.DisableHopByHopHeaderRemoval,
|
||||||
PathPrefix: "",
|
PathPrefix: "",
|
||||||
Version: sep.parent.Option.HostVersion,
|
Version: sep.parent.Option.HostVersion,
|
||||||
})
|
})
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
|
|
||||||
// Check if a user define header exists in this endpoint, ignore case
|
// Check if a user define header exists in this endpoint, ignore case
|
||||||
func (ep *ProxyEndpoint) UserDefinedHeaderExists(key string) bool {
|
func (ep *ProxyEndpoint) UserDefinedHeaderExists(key string) bool {
|
||||||
for _, header := range ep.UserDefinedHeaders {
|
for _, header := range ep.HeaderRewriteRules.UserDefinedHeaders {
|
||||||
if strings.EqualFold(header.Key, key) {
|
if strings.EqualFold(header.Key, key) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -38,13 +38,13 @@ func (ep *ProxyEndpoint) UserDefinedHeaderExists(key string) bool {
|
|||||||
// Remvoe a user defined header from the list
|
// Remvoe a user defined header from the list
|
||||||
func (ep *ProxyEndpoint) RemoveUserDefinedHeader(key string) error {
|
func (ep *ProxyEndpoint) RemoveUserDefinedHeader(key string) error {
|
||||||
newHeaderList := []*rewrite.UserDefinedHeader{}
|
newHeaderList := []*rewrite.UserDefinedHeader{}
|
||||||
for _, header := range ep.UserDefinedHeaders {
|
for _, header := range ep.HeaderRewriteRules.UserDefinedHeaders {
|
||||||
if !strings.EqualFold(header.Key, key) {
|
if !strings.EqualFold(header.Key, key) {
|
||||||
newHeaderList = append(newHeaderList, header)
|
newHeaderList = append(newHeaderList, header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ep.UserDefinedHeaders = newHeaderList
|
ep.HeaderRewriteRules.UserDefinedHeaders = newHeaderList
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ func (ep *ProxyEndpoint) AddUserDefinedHeader(newHeaderRule *rewrite.UserDefined
|
|||||||
}
|
}
|
||||||
|
|
||||||
newHeaderRule.Key = cases.Title(language.Und, cases.NoLower).String(newHeaderRule.Key)
|
newHeaderRule.Key = cases.Title(language.Und, cases.NoLower).String(newHeaderRule.Key)
|
||||||
ep.UserDefinedHeaders = append(ep.UserDefinedHeaders, newHeaderRule)
|
ep.HeaderRewriteRules.UserDefinedHeaders = append(ep.HeaderRewriteRules.UserDefinedHeaders, newHeaderRule)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,9 +123,9 @@ func (ep *ProxyEndpoint) AddVirtualDirectoryRule(vdir *VirtualDirectoryEndpoint)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if ep.ProxyType == ProxyType_Root {
|
if ep.ProxyType == ProxyTypeRoot {
|
||||||
parentRouter.Root = readyRoutingRule
|
parentRouter.Root = readyRoutingRule
|
||||||
} else if ep.ProxyType == ProxyType_Host {
|
} else if ep.ProxyType == ProxyTypeHost {
|
||||||
ep.Remove()
|
ep.Remove()
|
||||||
parentRouter.AddProxyRouteToRuntime(readyRoutingRule)
|
parentRouter.AddProxyRouteToRuntime(readyRoutingRule)
|
||||||
} else {
|
} else {
|
||||||
|
@ -145,6 +145,8 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
|
wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
|
||||||
SkipTLSValidation: selectedUpstream.SkipCertValidations,
|
SkipTLSValidation: selectedUpstream.SkipCertValidations,
|
||||||
SkipOriginCheck: selectedUpstream.SkipWebSocketOriginCheck,
|
SkipOriginCheck: selectedUpstream.SkipWebSocketOriginCheck,
|
||||||
|
CopyAllHeaders: true,
|
||||||
|
UserDefinedHeaders: target.HeaderRewriteRules.UserDefinedHeaders,
|
||||||
Logger: h.Parent.Option.Logger,
|
Logger: h.Parent.Option.Logger,
|
||||||
})
|
})
|
||||||
wspHandler.ServeHTTP(w, r)
|
wspHandler.ServeHTTP(w, r)
|
||||||
@ -160,15 +162,15 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Populate the user-defined headers with the values from the request
|
//Populate the user-defined headers with the values from the request
|
||||||
rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, target.UserDefinedHeaders)
|
rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, target.HeaderRewriteRules.UserDefinedHeaders)
|
||||||
|
|
||||||
//Build downstream and upstream header rules
|
//Build downstream and upstream header rules
|
||||||
upstreamHeaders, downstreamHeaders := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{
|
upstreamHeaders, downstreamHeaders := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{
|
||||||
UserDefinedHeaders: rewrittenUserDefinedHeaders,
|
UserDefinedHeaders: rewrittenUserDefinedHeaders,
|
||||||
HSTSMaxAge: target.HSTSMaxAge,
|
HSTSMaxAge: target.HeaderRewriteRules.HSTSMaxAge,
|
||||||
HSTSIncludeSubdomains: target.ContainsWildcardName(true),
|
HSTSIncludeSubdomains: target.ContainsWildcardName(true),
|
||||||
EnablePermissionPolicyHeader: target.EnablePermissionPolicyHeader,
|
EnablePermissionPolicyHeader: target.HeaderRewriteRules.EnablePermissionPolicyHeader,
|
||||||
PermissionPolicy: target.PermissionPolicy,
|
PermissionPolicy: target.HeaderRewriteRules.PermissionPolicy,
|
||||||
})
|
})
|
||||||
|
|
||||||
//Handle the request reverse proxy
|
//Handle the request reverse proxy
|
||||||
@ -180,8 +182,8 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
PathPrefix: "",
|
PathPrefix: "",
|
||||||
UpstreamHeaders: upstreamHeaders,
|
UpstreamHeaders: upstreamHeaders,
|
||||||
DownstreamHeaders: downstreamHeaders,
|
DownstreamHeaders: downstreamHeaders,
|
||||||
HostHeaderOverwrite: target.RequestHostOverwrite,
|
HostHeaderOverwrite: target.HeaderRewriteRules.RequestHostOverwrite,
|
||||||
NoRemoveHopByHop: target.DisableHopByHopHeaderRemoval,
|
NoRemoveHopByHop: target.HeaderRewriteRules.DisableHopByHopHeaderRemoval,
|
||||||
Version: target.parent.Option.HostVersion,
|
Version: target.parent.Option.HostVersion,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -223,6 +225,8 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
|
wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
|
||||||
SkipTLSValidation: target.SkipCertValidations,
|
SkipTLSValidation: target.SkipCertValidations,
|
||||||
SkipOriginCheck: true, //You should not use websocket via virtual directory. But keep this to true for compatibility
|
SkipOriginCheck: true, //You should not use websocket via virtual directory. But keep this to true for compatibility
|
||||||
|
CopyAllHeaders: true,
|
||||||
|
UserDefinedHeaders: target.parent.HeaderRewriteRules.UserDefinedHeaders,
|
||||||
Logger: h.Parent.Option.Logger,
|
Logger: h.Parent.Option.Logger,
|
||||||
})
|
})
|
||||||
wspHandler.ServeHTTP(w, r)
|
wspHandler.ServeHTTP(w, r)
|
||||||
@ -238,15 +242,15 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Populate the user-defined headers with the values from the request
|
//Populate the user-defined headers with the values from the request
|
||||||
rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, target.parent.UserDefinedHeaders)
|
rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, target.parent.HeaderRewriteRules.UserDefinedHeaders)
|
||||||
|
|
||||||
//Build downstream and upstream header rules, use the parent (subdomain) endpoint's headers
|
//Build downstream and upstream header rules, use the parent (subdomain) endpoint's headers
|
||||||
upstreamHeaders, downstreamHeaders := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{
|
upstreamHeaders, downstreamHeaders := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{
|
||||||
UserDefinedHeaders: rewrittenUserDefinedHeaders,
|
UserDefinedHeaders: rewrittenUserDefinedHeaders,
|
||||||
HSTSMaxAge: target.parent.HSTSMaxAge,
|
HSTSMaxAge: target.parent.HeaderRewriteRules.HSTSMaxAge,
|
||||||
HSTSIncludeSubdomains: target.parent.ContainsWildcardName(true),
|
HSTSIncludeSubdomains: target.parent.ContainsWildcardName(true),
|
||||||
EnablePermissionPolicyHeader: target.parent.EnablePermissionPolicyHeader,
|
EnablePermissionPolicyHeader: target.parent.HeaderRewriteRules.EnablePermissionPolicyHeader,
|
||||||
PermissionPolicy: target.parent.PermissionPolicy,
|
PermissionPolicy: target.parent.HeaderRewriteRules.PermissionPolicy,
|
||||||
})
|
})
|
||||||
|
|
||||||
//Handle the virtual directory reverse proxy request
|
//Handle the virtual directory reverse proxy request
|
||||||
@ -257,7 +261,7 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
PathPrefix: target.MatchingPath,
|
PathPrefix: target.MatchingPath,
|
||||||
UpstreamHeaders: upstreamHeaders,
|
UpstreamHeaders: upstreamHeaders,
|
||||||
DownstreamHeaders: downstreamHeaders,
|
DownstreamHeaders: downstreamHeaders,
|
||||||
HostHeaderOverwrite: target.parent.RequestHostOverwrite,
|
HostHeaderOverwrite: target.parent.HeaderRewriteRules.RequestHostOverwrite,
|
||||||
Version: target.parent.parent.Option.HostVersion,
|
Version: target.parent.parent.Option.HostVersion,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -19,10 +19,12 @@ import (
|
|||||||
"imuslab.com/zoraxy/mod/tlscert"
|
"imuslab.com/zoraxy/mod/tlscert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ProxyType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProxyType_Root = 0
|
ProxyTypeRoot ProxyType = iota //Root Proxy, everything not matching will be routed here
|
||||||
ProxyType_Host = 1
|
ProxyTypeHost //Host Proxy, match by host (domain) name
|
||||||
ProxyType_Vdir = 2
|
ProxyTypeVdir //Virtual Directory Proxy, match by path prefix
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProxyHandler struct {
|
type ProxyHandler struct {
|
||||||
@ -53,14 +55,14 @@ type RouterOption struct {
|
|||||||
/* Router Object */
|
/* Router Object */
|
||||||
type Router struct {
|
type Router struct {
|
||||||
Option *RouterOption
|
Option *RouterOption
|
||||||
ProxyEndpoints *sync.Map
|
ProxyEndpoints *sync.Map //Map of ProxyEndpoint objects, each ProxyEndpoint object is a routing rule that handle incoming requests
|
||||||
Running bool
|
Running bool //If the router is running
|
||||||
Root *ProxyEndpoint
|
Root *ProxyEndpoint //Root proxy endpoint, default site
|
||||||
mux http.Handler
|
mux http.Handler //HTTP handler
|
||||||
server *http.Server
|
server *http.Server //HTTP server
|
||||||
tlsListener net.Listener
|
tlsListener net.Listener //TLS listener, handle SNI routing
|
||||||
loadBalancer *loadbalance.RouteManager //Load balancer routing manager
|
loadBalancer *loadbalance.RouteManager //Load balancer routing manager
|
||||||
routingRules []*RoutingRule
|
routingRules []*RoutingRule //Special routing rules, handle high priority routing like ACME request handling
|
||||||
|
|
||||||
tlsRedirectStop chan bool //Stop channel for tls redirection server
|
tlsRedirectStop chan bool //Stop channel for tls redirection server
|
||||||
rateLimterStop chan bool //Stop channel for rate limiter
|
rateLimterStop chan bool //Stop channel for rate limiter
|
||||||
@ -99,9 +101,42 @@ type VirtualDirectoryEndpoint struct {
|
|||||||
parent *ProxyEndpoint `json:"-"`
|
parent *ProxyEndpoint `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rules and settings for header rewriting
|
||||||
|
type HeaderRewriteRules struct {
|
||||||
|
UserDefinedHeaders []*rewrite.UserDefinedHeader //Custom headers to append when proxying requests from this endpoint
|
||||||
|
RequestHostOverwrite string //If not empty, this domain will be used to overwrite the Host field in request header
|
||||||
|
HSTSMaxAge int64 //HSTS max age, set to 0 for disable HSTS headers
|
||||||
|
EnablePermissionPolicyHeader bool //Enable injection of permission policy header
|
||||||
|
PermissionPolicy *permissionpolicy.PermissionsPolicy //Permission policy header
|
||||||
|
DisableHopByHopHeaderRemoval bool //Do not remove hop-by-hop headers
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Authentication Provider
|
||||||
|
|
||||||
|
TODO: Move these into a dedicated module
|
||||||
|
*/
|
||||||
|
|
||||||
|
type AuthMethod int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AuthMethodNone AuthMethod = iota //No authentication required
|
||||||
|
AuthMethodBasic //Basic Auth
|
||||||
|
AuthMethodAuthelia //Authelia
|
||||||
|
AuthMethodOauth2 //Oauth2
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuthenticationProvider struct {
|
||||||
|
AuthMethod AuthMethod //The authentication method to use
|
||||||
|
BasicAuthCredentials []*BasicAuthCredentials //Basic auth credentials
|
||||||
|
BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
|
||||||
|
}
|
||||||
|
|
||||||
// A proxy endpoint record, a general interface for handling inbound routing
|
// A proxy endpoint record, a general interface for handling inbound routing
|
||||||
type ProxyEndpoint struct {
|
type ProxyEndpoint struct {
|
||||||
ProxyType int //The type of this proxy, see const def
|
ProxyType ProxyType //The type of this proxy, see const def
|
||||||
RootOrMatchingDomain string //Matching domain for host, also act as key
|
RootOrMatchingDomain string //Matching domain for host, also act as key
|
||||||
MatchingDomainAlias []string //A list of domains that alias to this rule
|
MatchingDomainAlias []string //A list of domains that alias to this rule
|
||||||
ActiveOrigins []*loadbalance.Upstream //Activated Upstream or origin servers IP or domain to proxy to
|
ActiveOrigins []*loadbalance.Upstream //Activated Upstream or origin servers IP or domain to proxy to
|
||||||
@ -117,23 +152,18 @@ type ProxyEndpoint struct {
|
|||||||
VirtualDirectories []*VirtualDirectoryEndpoint
|
VirtualDirectories []*VirtualDirectoryEndpoint
|
||||||
|
|
||||||
//Custom Headers
|
//Custom Headers
|
||||||
UserDefinedHeaders []*rewrite.UserDefinedHeader //Custom headers to append when proxying requests from this endpoint
|
HeaderRewriteRules *HeaderRewriteRules
|
||||||
RequestHostOverwrite string //If not empty, this domain will be used to overwrite the Host field in request header
|
|
||||||
HSTSMaxAge int64 //HSTS max age, set to 0 for disable HSTS headers
|
|
||||||
EnablePermissionPolicyHeader bool //Enable injection of permission policy header
|
|
||||||
PermissionPolicy *permissionpolicy.PermissionsPolicy //Permission policy header
|
|
||||||
DisableHopByHopHeaderRemoval bool //Do not remove hop-by-hop headers
|
|
||||||
|
|
||||||
//Authentication
|
//Authentication
|
||||||
RequireBasicAuth bool //Set to true to request basic auth before proxy
|
AuthenticationProvider *AuthenticationProvider
|
||||||
BasicAuthCredentials []*BasicAuthCredentials //Basic auth credentials
|
|
||||||
BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
|
|
||||||
UseSSOIntercept bool //Allow SSO to intercept this endpoint and provide authentication via Oauth2 credentials
|
|
||||||
|
|
||||||
// Rate Limiting
|
// Rate Limiting
|
||||||
RequireRateLimit bool
|
RequireRateLimit bool
|
||||||
RateLimit int64 // Rate limit in requests per second
|
RateLimit int64 // Rate limit in requests per second
|
||||||
|
|
||||||
|
//Uptime Monitor
|
||||||
|
DisableUptimeMonitor bool //Disable uptime monitor for this endpoint
|
||||||
|
|
||||||
//Access Control
|
//Access Control
|
||||||
AccessFilterUUID string //Access filter ID
|
AccessFilterUUID string //Access filter ID
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package update
|
package update
|
||||||
|
|
||||||
import v308 "imuslab.com/zoraxy/mod/update/v308"
|
import (
|
||||||
|
v308 "imuslab.com/zoraxy/mod/update/v308"
|
||||||
|
v315 "imuslab.com/zoraxy/mod/update/v315"
|
||||||
|
)
|
||||||
|
|
||||||
// Updater Core logic
|
// Updater Core logic
|
||||||
func runUpdateRoutineWithVersion(fromVersion int, toVersion int) {
|
func runUpdateRoutineWithVersion(fromVersion int, toVersion int) {
|
||||||
@ -10,6 +13,12 @@ func runUpdateRoutineWithVersion(fromVersion int, toVersion int) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
} else if fromVersion == 314 && toVersion == 315 {
|
||||||
|
//Updating from v3.1.4 to v3.1.5
|
||||||
|
err := v315.UpdateFrom314To315()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ADD MORE VERSIONS HERE
|
//ADD MORE VERSIONS HERE
|
||||||
|
24
src/mod/update/updateutil/updateutil.go
Normal file
24
src/mod/update/updateutil/updateutil.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package updateutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Helper function to copy files
|
||||||
|
func CopyFile(src, dst string) error {
|
||||||
|
sourceFile, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer sourceFile.Close()
|
||||||
|
|
||||||
|
destinationFile, err := os.Create(dst)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer destinationFile.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(destinationFile, sourceFile)
|
||||||
|
return err
|
||||||
|
}
|
50
src/mod/update/v315/typedef314.go
Normal file
50
src/mod/update/v315/typedef314.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package v315
|
||||||
|
|
||||||
|
import (
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy/loadbalance"
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy/rewrite"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A proxy endpoint record, a general interface for handling inbound routing
|
||||||
|
type v314ProxyEndpoint struct {
|
||||||
|
ProxyType int //The type of this proxy, see const def
|
||||||
|
RootOrMatchingDomain string //Matching domain for host, also act as key
|
||||||
|
MatchingDomainAlias []string //A list of domains that alias to this rule
|
||||||
|
ActiveOrigins []*loadbalance.Upstream //Activated Upstream or origin servers IP or domain to proxy to
|
||||||
|
InactiveOrigins []*loadbalance.Upstream //Disabled Upstream or origin servers IP or domain to proxy to
|
||||||
|
UseStickySession bool //Use stick session for load balancing
|
||||||
|
UseActiveLoadBalance bool //Use active loadbalancing, default passive
|
||||||
|
Disabled bool //If the rule is disabled
|
||||||
|
|
||||||
|
//Inbound TLS/SSL Related
|
||||||
|
BypassGlobalTLS bool //Bypass global TLS setting options if TLS Listener enabled (parent.tlsListener != nil)
|
||||||
|
|
||||||
|
//Virtual Directories
|
||||||
|
VirtualDirectories []*VirtualDirectoryEndpoint
|
||||||
|
|
||||||
|
//Custom Headers
|
||||||
|
UserDefinedHeaders []*rewrite.UserDefinedHeader //Custom headers to append when proxying requests from this endpoint
|
||||||
|
RequestHostOverwrite string //If not empty, this domain will be used to overwrite the Host field in request header
|
||||||
|
HSTSMaxAge int64 //HSTS max age, set to 0 for disable HSTS headers
|
||||||
|
EnablePermissionPolicyHeader bool //Enable injection of permission policy header
|
||||||
|
PermissionPolicy *permissionpolicy.PermissionsPolicy //Permission policy header
|
||||||
|
DisableHopByHopHeaderRemoval bool //Do not remove hop-by-hop headers
|
||||||
|
|
||||||
|
//Authentication
|
||||||
|
RequireBasicAuth bool //Set to true to request basic auth before proxy
|
||||||
|
BasicAuthCredentials []*BasicAuthCredentials //Basic auth credentials
|
||||||
|
BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
|
||||||
|
UseSSOIntercept bool //Allow SSO to intercept this endpoint and provide authentication via Oauth2 credentials
|
||||||
|
|
||||||
|
// Rate Limiting
|
||||||
|
RequireRateLimit bool
|
||||||
|
RateLimit int64 // Rate limit in requests per second
|
||||||
|
|
||||||
|
//Access Control
|
||||||
|
AccessFilterUUID string //Access filter ID
|
||||||
|
|
||||||
|
//Fallback routing logic (Special Rule Sets Only)
|
||||||
|
DefaultSiteOption int //Fallback routing logic options
|
||||||
|
DefaultSiteValue string //Fallback routing target, optional
|
||||||
|
}
|
106
src/mod/update/v315/typedef315.go
Normal file
106
src/mod/update/v315/typedef315.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package v315
|
||||||
|
|
||||||
|
import (
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy/loadbalance"
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy/rewrite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProxyType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProxyTypeRoot ProxyType = iota //Root Proxy, everything not matching will be routed here
|
||||||
|
ProxyTypeHost //Host Proxy, match by host (domain) name
|
||||||
|
ProxyTypeVdir //Virtual Directory Proxy, match by path prefix
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Basic Auth Related Data structure*/
|
||||||
|
// Auth credential for basic auth on certain endpoints
|
||||||
|
type BasicAuthCredentials struct {
|
||||||
|
Username string
|
||||||
|
PasswordHash string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auth credential for basic auth on certain endpoints
|
||||||
|
type BasicAuthUnhashedCredentials struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paths to exclude in basic auth enabled proxy handler
|
||||||
|
type BasicAuthExceptionRule struct {
|
||||||
|
PathPrefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Routing Rule Data Structures */
|
||||||
|
|
||||||
|
// A Virtual Directory endpoint, provide a subset of ProxyEndpoint for better
|
||||||
|
// program structure than directly using ProxyEndpoint
|
||||||
|
type VirtualDirectoryEndpoint struct {
|
||||||
|
MatchingPath string //Matching prefix of the request path, also act as key
|
||||||
|
Domain string //Domain or IP to proxy to
|
||||||
|
RequireTLS bool //Target domain require TLS
|
||||||
|
SkipCertValidations bool //Set to true to accept self signed certs
|
||||||
|
Disabled bool //If the rule is enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rules and settings for header rewriting
|
||||||
|
type HeaderRewriteRules struct {
|
||||||
|
UserDefinedHeaders []*rewrite.UserDefinedHeader //Custom headers to append when proxying requests from this endpoint
|
||||||
|
RequestHostOverwrite string //If not empty, this domain will be used to overwrite the Host field in request header
|
||||||
|
HSTSMaxAge int64 //HSTS max age, set to 0 for disable HSTS headers
|
||||||
|
EnablePermissionPolicyHeader bool //Enable injection of permission policy header
|
||||||
|
PermissionPolicy *permissionpolicy.PermissionsPolicy //Permission policy header
|
||||||
|
DisableHopByHopHeaderRemoval bool //Do not remove hop-by-hop headers
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthProvider int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AuthProviderNone AuthProvider = iota
|
||||||
|
AuthProviderBasicAuth
|
||||||
|
AuthProviderAuthelia
|
||||||
|
AuthProviderOauth2
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuthenticationProvider struct {
|
||||||
|
AuthProvider AuthProvider //The type of authentication provider
|
||||||
|
RequireBasicAuth bool //Set to true to request basic auth before proxy
|
||||||
|
BasicAuthCredentials []*BasicAuthCredentials //Basic auth credentials
|
||||||
|
BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
|
||||||
|
}
|
||||||
|
|
||||||
|
// A proxy endpoint record, a general interface for handling inbound routing
|
||||||
|
type v315ProxyEndpoint struct {
|
||||||
|
ProxyType ProxyType //The type of this proxy, see const def
|
||||||
|
RootOrMatchingDomain string //Matching domain for host, also act as key
|
||||||
|
MatchingDomainAlias []string //A list of domains that alias to this rule
|
||||||
|
ActiveOrigins []*loadbalance.Upstream //Activated Upstream or origin servers IP or domain to proxy to
|
||||||
|
InactiveOrigins []*loadbalance.Upstream //Disabled Upstream or origin servers IP or domain to proxy to
|
||||||
|
UseStickySession bool //Use stick session for load balancing
|
||||||
|
UseActiveLoadBalance bool //Use active loadbalancing, default passive
|
||||||
|
Disabled bool //If the rule is disabled
|
||||||
|
|
||||||
|
//Inbound TLS/SSL Related
|
||||||
|
BypassGlobalTLS bool //Bypass global TLS setting options if TLS Listener enabled (parent.tlsListener != nil)
|
||||||
|
|
||||||
|
//Virtual Directories
|
||||||
|
VirtualDirectories []*VirtualDirectoryEndpoint
|
||||||
|
|
||||||
|
//Custom Headers
|
||||||
|
HeaderRewriteRules *HeaderRewriteRules
|
||||||
|
|
||||||
|
//Authentication
|
||||||
|
AuthenticationProvider *AuthenticationProvider
|
||||||
|
|
||||||
|
// Rate Limiting
|
||||||
|
RequireRateLimit bool
|
||||||
|
RateLimit int64 // Rate limit in requests per second
|
||||||
|
|
||||||
|
//Access Control
|
||||||
|
AccessFilterUUID string //Access filter ID
|
||||||
|
|
||||||
|
//Fallback routing logic (Special Rule Sets Only)
|
||||||
|
DefaultSiteOption int //Fallback routing logic options
|
||||||
|
DefaultSiteValue string //Fallback routing target, optional
|
||||||
|
}
|
124
src/mod/update/v315/v315.go
Normal file
124
src/mod/update/v315/v315.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package v315
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"imuslab.com/zoraxy/mod/update/updateutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UpdateFrom314To315() error {
|
||||||
|
//Load the configs
|
||||||
|
oldConfigFiles, err := filepath.Glob("./conf/proxy/*.config")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Backup all the files
|
||||||
|
err = os.MkdirAll("./conf/proxy-314.old/", 0775)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, oldConfigFile := range oldConfigFiles {
|
||||||
|
// Extract the file name from the path
|
||||||
|
fileName := filepath.Base(oldConfigFile)
|
||||||
|
// Construct the backup file path
|
||||||
|
backupFile := filepath.Join("./conf/proxy-314.old/", fileName)
|
||||||
|
|
||||||
|
// Copy the file to the backup directory
|
||||||
|
err := updateutil.CopyFile(oldConfigFile, backupFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//read the config into the old struct
|
||||||
|
for _, oldConfigFile := range oldConfigFiles {
|
||||||
|
configContent, err := os.ReadFile(oldConfigFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Unable to read config file "+filepath.Base(oldConfigFile), err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
thisOldConfigStruct := v314ProxyEndpoint{}
|
||||||
|
err = json.Unmarshal(configContent, &thisOldConfigStruct)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Unable to parse file "+filepath.Base(oldConfigFile), err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert the old struct to the new struct
|
||||||
|
thisNewConfigStruct := convertV314ToV315(thisOldConfigStruct)
|
||||||
|
|
||||||
|
//Write the new config to file
|
||||||
|
newConfigContent, err := json.MarshalIndent(thisNewConfigStruct, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Unable to marshal new config "+filepath.Base(oldConfigFile), err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(oldConfigFile, newConfigContent, 0664)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Unable to write new config "+filepath.Base(oldConfigFile), err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertV314ToV315(thisOldConfigStruct v314ProxyEndpoint) v315ProxyEndpoint {
|
||||||
|
//Move old header and auth configs into struct
|
||||||
|
newHeaderRewriteRules := HeaderRewriteRules{
|
||||||
|
UserDefinedHeaders: thisOldConfigStruct.UserDefinedHeaders,
|
||||||
|
RequestHostOverwrite: thisOldConfigStruct.RequestHostOverwrite,
|
||||||
|
HSTSMaxAge: thisOldConfigStruct.HSTSMaxAge,
|
||||||
|
EnablePermissionPolicyHeader: thisOldConfigStruct.EnablePermissionPolicyHeader,
|
||||||
|
PermissionPolicy: thisOldConfigStruct.PermissionPolicy,
|
||||||
|
DisableHopByHopHeaderRemoval: thisOldConfigStruct.DisableHopByHopHeaderRemoval,
|
||||||
|
}
|
||||||
|
|
||||||
|
newAuthenticationProvider := AuthenticationProvider{
|
||||||
|
RequireBasicAuth: thisOldConfigStruct.RequireBasicAuth,
|
||||||
|
BasicAuthCredentials: thisOldConfigStruct.BasicAuthCredentials,
|
||||||
|
BasicAuthExceptionRules: thisOldConfigStruct.BasicAuthExceptionRules,
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert proxy type int to enum
|
||||||
|
var newConfigProxyType ProxyType
|
||||||
|
if thisOldConfigStruct.ProxyType == 0 {
|
||||||
|
newConfigProxyType = ProxyTypeRoot
|
||||||
|
} else if thisOldConfigStruct.ProxyType == 1 {
|
||||||
|
newConfigProxyType = ProxyTypeHost
|
||||||
|
} else if thisOldConfigStruct.ProxyType == 2 {
|
||||||
|
newConfigProxyType = ProxyTypeVdir
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update the config struct
|
||||||
|
thisNewConfigStruct := v315ProxyEndpoint{
|
||||||
|
ProxyType: newConfigProxyType,
|
||||||
|
RootOrMatchingDomain: thisOldConfigStruct.RootOrMatchingDomain,
|
||||||
|
MatchingDomainAlias: thisOldConfigStruct.MatchingDomainAlias,
|
||||||
|
ActiveOrigins: thisOldConfigStruct.ActiveOrigins,
|
||||||
|
InactiveOrigins: thisOldConfigStruct.InactiveOrigins,
|
||||||
|
UseStickySession: thisOldConfigStruct.UseStickySession,
|
||||||
|
UseActiveLoadBalance: thisOldConfigStruct.UseActiveLoadBalance,
|
||||||
|
Disabled: thisOldConfigStruct.Disabled,
|
||||||
|
BypassGlobalTLS: thisOldConfigStruct.BypassGlobalTLS,
|
||||||
|
VirtualDirectories: thisOldConfigStruct.VirtualDirectories,
|
||||||
|
RequireRateLimit: thisOldConfigStruct.RequireRateLimit,
|
||||||
|
RateLimit: thisOldConfigStruct.RateLimit,
|
||||||
|
AccessFilterUUID: thisOldConfigStruct.AccessFilterUUID,
|
||||||
|
DefaultSiteOption: thisOldConfigStruct.DefaultSiteOption,
|
||||||
|
DefaultSiteValue: thisOldConfigStruct.DefaultSiteValue,
|
||||||
|
|
||||||
|
//Append the new struct into the new config
|
||||||
|
HeaderRewriteRules: &newHeaderRewriteRules,
|
||||||
|
AuthenticationProvider: &newAuthenticationProvider,
|
||||||
|
}
|
||||||
|
|
||||||
|
return thisNewConfigStruct
|
||||||
|
}
|
@ -13,6 +13,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy/rewrite"
|
||||||
"imuslab.com/zoraxy/mod/info/logger"
|
"imuslab.com/zoraxy/mod/info/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,6 +59,8 @@ type WebsocketProxy struct {
|
|||||||
type Options struct {
|
type Options struct {
|
||||||
SkipTLSValidation bool //Skip backend TLS validation
|
SkipTLSValidation bool //Skip backend TLS validation
|
||||||
SkipOriginCheck bool //Skip origin check
|
SkipOriginCheck bool //Skip origin check
|
||||||
|
CopyAllHeaders bool //Copy all headers from incoming request to backend request
|
||||||
|
UserDefinedHeaders []*rewrite.UserDefinedHeader //User defined headers
|
||||||
Logger *logger.Logger //Logger, can be nil
|
Logger *logger.Logger //Logger, can be nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +81,14 @@ func NewProxy(target *url.URL, options Options) *WebsocketProxy {
|
|||||||
u.RawQuery = r.URL.RawQuery
|
u.RawQuery = r.URL.RawQuery
|
||||||
return &u
|
return &u
|
||||||
}
|
}
|
||||||
return &WebsocketProxy{Backend: backend, Verbal: false, Options: options}
|
|
||||||
|
// Create a new websocket proxy
|
||||||
|
wsprox := &WebsocketProxy{Backend: backend, Verbal: false, Options: options}
|
||||||
|
if options.CopyAllHeaders {
|
||||||
|
wsprox.Director = DefaultDirector
|
||||||
|
}
|
||||||
|
|
||||||
|
return wsprox
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utilities function for log printing
|
// Utilities function for log printing
|
||||||
@ -90,6 +100,35 @@ func (w *WebsocketProxy) Println(messsage string, err error) {
|
|||||||
log.Println("[websocketproxy] [system:info]"+messsage, err)
|
log.Println("[websocketproxy] [system:info]"+messsage, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultDirector is the default implementation of Director, which copies
|
||||||
|
// all headers from the incoming request to the outgoing request.
|
||||||
|
func DefaultDirector(r *http.Request, h http.Header) {
|
||||||
|
//Copy all header values from request to target header
|
||||||
|
for k, vv := range r.Header {
|
||||||
|
for _, v := range vv {
|
||||||
|
h.Set(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove hop-by-hop headers
|
||||||
|
for _, removePendingHeader := range []string{
|
||||||
|
"Connection",
|
||||||
|
"Keep-Alive",
|
||||||
|
"Proxy-Authenticate",
|
||||||
|
"Proxy-Authorization",
|
||||||
|
"Te",
|
||||||
|
"Trailers",
|
||||||
|
"Transfer-Encoding",
|
||||||
|
"Sec-WebSocket-Extensions",
|
||||||
|
"Sec-WebSocket-Key",
|
||||||
|
"Sec-WebSocket-Protocol",
|
||||||
|
"Sec-WebSocket-Version",
|
||||||
|
"Upgrade",
|
||||||
|
} {
|
||||||
|
h.Del(removePendingHeader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ServeHTTP implements the http.Handler that proxies WebSocket connections.
|
// ServeHTTP implements the http.Handler that proxies WebSocket connections.
|
||||||
func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
if w.Backend == nil {
|
if w.Backend == nil {
|
||||||
@ -162,6 +201,15 @@ func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
w.Director(req, requestHeader)
|
w.Director(req, requestHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace header variables and copy user-defined headers
|
||||||
|
rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(req, w.Options.UserDefinedHeaders)
|
||||||
|
upstreamHeaders, _ := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{
|
||||||
|
UserDefinedHeaders: rewrittenUserDefinedHeaders,
|
||||||
|
})
|
||||||
|
for _, headerValuePair := range upstreamHeaders {
|
||||||
|
requestHeader.Set(headerValuePair[0], headerValuePair[1])
|
||||||
|
}
|
||||||
|
|
||||||
// Connect to the backend URL, also pass the headers we get from the requst
|
// Connect to the backend URL, also pass the headers we get from the requst
|
||||||
// together with the Forwarded headers we prepared above.
|
// together with the Forwarded headers we prepared above.
|
||||||
// TODO: support multiplexing on the same backend connection instead of
|
// TODO: support multiplexing on the same backend connection instead of
|
||||||
|
@ -309,10 +309,25 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Generate a default authenticaion provider
|
||||||
|
authMethod := dynamicproxy.AuthMethodNone
|
||||||
|
if requireBasicAuth {
|
||||||
|
authMethod = dynamicproxy.AuthMethodBasic
|
||||||
|
}
|
||||||
|
thisAuthenticationProvider := dynamicproxy.AuthenticationProvider{
|
||||||
|
AuthMethod: authMethod,
|
||||||
|
BasicAuthCredentials: basicAuthCredentials,
|
||||||
|
BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
|
||||||
|
}
|
||||||
|
|
||||||
|
thisCustomHeaderRules := dynamicproxy.HeaderRewriteRules{
|
||||||
|
UserDefinedHeaders: []*rewrite.UserDefinedHeader{},
|
||||||
|
}
|
||||||
|
|
||||||
//Generate a proxy endpoint object
|
//Generate a proxy endpoint object
|
||||||
thisProxyEndpoint := dynamicproxy.ProxyEndpoint{
|
thisProxyEndpoint := dynamicproxy.ProxyEndpoint{
|
||||||
//I/O
|
//I/O
|
||||||
ProxyType: dynamicproxy.ProxyType_Host,
|
ProxyType: dynamicproxy.ProxyTypeHost,
|
||||||
RootOrMatchingDomain: rootOrMatchingDomain,
|
RootOrMatchingDomain: rootOrMatchingDomain,
|
||||||
MatchingDomainAlias: aliasHostnames,
|
MatchingDomainAlias: aliasHostnames,
|
||||||
ActiveOrigins: []*loadbalance.Upstream{
|
ActiveOrigins: []*loadbalance.Upstream{
|
||||||
@ -333,11 +348,14 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
|
|||||||
//VDir
|
//VDir
|
||||||
VirtualDirectories: []*dynamicproxy.VirtualDirectoryEndpoint{},
|
VirtualDirectories: []*dynamicproxy.VirtualDirectoryEndpoint{},
|
||||||
//Custom headers
|
//Custom headers
|
||||||
UserDefinedHeaders: []*rewrite.UserDefinedHeader{},
|
|
||||||
//Auth
|
//Auth
|
||||||
RequireBasicAuth: requireBasicAuth,
|
AuthenticationProvider: &thisAuthenticationProvider,
|
||||||
BasicAuthCredentials: basicAuthCredentials,
|
|
||||||
BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
|
//Header Rewrite
|
||||||
|
HeaderRewriteRules: &thisCustomHeaderRules,
|
||||||
|
|
||||||
|
//Default Site
|
||||||
DefaultSiteOption: 0,
|
DefaultSiteOption: 0,
|
||||||
DefaultSiteValue: "",
|
DefaultSiteValue: "",
|
||||||
// Rate Limit
|
// Rate Limit
|
||||||
@ -379,7 +397,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
//Write the root options to file
|
//Write the root options to file
|
||||||
rootRoutingEndpoint := dynamicproxy.ProxyEndpoint{
|
rootRoutingEndpoint := dynamicproxy.ProxyEndpoint{
|
||||||
ProxyType: dynamicproxy.ProxyType_Root,
|
ProxyType: dynamicproxy.ProxyTypeRoot,
|
||||||
RootOrMatchingDomain: "/",
|
RootOrMatchingDomain: "/",
|
||||||
ActiveOrigins: []*loadbalance.Upstream{
|
ActiveOrigins: []*loadbalance.Upstream{
|
||||||
{
|
{
|
||||||
@ -494,7 +512,19 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
|
|||||||
//Generate a new proxyEndpoint from the new config
|
//Generate a new proxyEndpoint from the new config
|
||||||
newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry)
|
newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry)
|
||||||
newProxyEndpoint.BypassGlobalTLS = bypassGlobalTLS
|
newProxyEndpoint.BypassGlobalTLS = bypassGlobalTLS
|
||||||
newProxyEndpoint.RequireBasicAuth = requireBasicAuth
|
if newProxyEndpoint.AuthenticationProvider == nil {
|
||||||
|
newProxyEndpoint.AuthenticationProvider = &dynamicproxy.AuthenticationProvider{
|
||||||
|
AuthMethod: dynamicproxy.AuthMethodNone,
|
||||||
|
BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{},
|
||||||
|
BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if requireBasicAuth {
|
||||||
|
newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodBasic
|
||||||
|
} else {
|
||||||
|
newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodNone
|
||||||
|
}
|
||||||
|
|
||||||
newProxyEndpoint.RequireRateLimit = requireRateLimit
|
newProxyEndpoint.RequireRateLimit = requireRateLimit
|
||||||
newProxyEndpoint.RateLimit = proxyRateLimit
|
newProxyEndpoint.RateLimit = proxyRateLimit
|
||||||
newProxyEndpoint.UseStickySession = useStickySession
|
newProxyEndpoint.UseStickySession = useStickySession
|
||||||
@ -624,7 +654,7 @@ func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
usernames := []string{}
|
usernames := []string{}
|
||||||
for _, cred := range targetProxy.BasicAuthCredentials {
|
for _, cred := range targetProxy.AuthenticationProvider.BasicAuthCredentials {
|
||||||
usernames = append(usernames, cred.Username)
|
usernames = append(usernames, cred.Username)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,7 +698,7 @@ func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
|
|||||||
if credential.Password == "" {
|
if credential.Password == "" {
|
||||||
//Check if exists in the old credential files
|
//Check if exists in the old credential files
|
||||||
keepUnchange := false
|
keepUnchange := false
|
||||||
for _, oldCredEntry := range targetProxy.BasicAuthCredentials {
|
for _, oldCredEntry := range targetProxy.AuthenticationProvider.BasicAuthCredentials {
|
||||||
if oldCredEntry.Username == credential.Username {
|
if oldCredEntry.Username == credential.Username {
|
||||||
//Exists! Reuse the old hash
|
//Exists! Reuse the old hash
|
||||||
mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
|
mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
|
||||||
@ -693,7 +723,7 @@ func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
targetProxy.BasicAuthCredentials = mergedCredentials
|
targetProxy.AuthenticationProvider.BasicAuthCredentials = mergedCredentials
|
||||||
|
|
||||||
//Save it to file
|
//Save it to file
|
||||||
SaveReverseProxyConfig(targetProxy)
|
SaveReverseProxyConfig(targetProxy)
|
||||||
@ -727,7 +757,7 @@ func ListProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//List all the exception paths for this proxy
|
//List all the exception paths for this proxy
|
||||||
results := targetProxy.BasicAuthExceptionRules
|
results := targetProxy.AuthenticationProvider.BasicAuthExceptionRules
|
||||||
if results == nil {
|
if results == nil {
|
||||||
//It is a config from a really old version of zoraxy. Overwrite it with empty array
|
//It is a config from a really old version of zoraxy. Overwrite it with empty array
|
||||||
results = []*dynamicproxy.BasicAuthExceptionRule{}
|
results = []*dynamicproxy.BasicAuthExceptionRule{}
|
||||||
@ -764,7 +794,7 @@ func AddProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
//Add a new exception rule if it is not already exists
|
//Add a new exception rule if it is not already exists
|
||||||
alreadyExists := false
|
alreadyExists := false
|
||||||
for _, thisExceptionRule := range targetProxy.BasicAuthExceptionRules {
|
for _, thisExceptionRule := range targetProxy.AuthenticationProvider.BasicAuthExceptionRules {
|
||||||
if thisExceptionRule.PathPrefix == matchingPrefix {
|
if thisExceptionRule.PathPrefix == matchingPrefix {
|
||||||
alreadyExists = true
|
alreadyExists = true
|
||||||
break
|
break
|
||||||
@ -774,7 +804,7 @@ func AddProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
|
|||||||
utils.SendErrorResponse(w, "This matching path already exists")
|
utils.SendErrorResponse(w, "This matching path already exists")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetProxy.BasicAuthExceptionRules = append(targetProxy.BasicAuthExceptionRules, &dynamicproxy.BasicAuthExceptionRule{
|
targetProxy.AuthenticationProvider.BasicAuthExceptionRules = append(targetProxy.AuthenticationProvider.BasicAuthExceptionRules, &dynamicproxy.BasicAuthExceptionRule{
|
||||||
PathPrefix: strings.TrimSpace(matchingPrefix),
|
PathPrefix: strings.TrimSpace(matchingPrefix),
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -808,7 +838,7 @@ func RemoveProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request)
|
|||||||
|
|
||||||
newExceptionRuleList := []*dynamicproxy.BasicAuthExceptionRule{}
|
newExceptionRuleList := []*dynamicproxy.BasicAuthExceptionRule{}
|
||||||
matchingExists := false
|
matchingExists := false
|
||||||
for _, thisExceptionalRule := range targetProxy.BasicAuthExceptionRules {
|
for _, thisExceptionalRule := range targetProxy.AuthenticationProvider.BasicAuthExceptionRules {
|
||||||
if thisExceptionalRule.PathPrefix != matchingPrefix {
|
if thisExceptionalRule.PathPrefix != matchingPrefix {
|
||||||
newExceptionRuleList = append(newExceptionRuleList, thisExceptionalRule)
|
newExceptionRuleList = append(newExceptionRuleList, thisExceptionalRule)
|
||||||
} else {
|
} else {
|
||||||
@ -821,7 +851,7 @@ func RemoveProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
targetProxy.BasicAuthExceptionRules = newExceptionRuleList
|
targetProxy.AuthenticationProvider.BasicAuthExceptionRules = newExceptionRuleList
|
||||||
|
|
||||||
// Save configs to runtime and file
|
// Save configs to runtime and file
|
||||||
targetProxy.UpdateToRuntime()
|
targetProxy.UpdateToRuntime()
|
||||||
@ -914,13 +944,13 @@ func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
|
|||||||
thisEndpoint := dynamicproxy.CopyEndpoint(value.(*dynamicproxy.ProxyEndpoint))
|
thisEndpoint := dynamicproxy.CopyEndpoint(value.(*dynamicproxy.ProxyEndpoint))
|
||||||
//Clear the auth passwords before showing to front-end
|
//Clear the auth passwords before showing to front-end
|
||||||
cleanedCredentials := []*dynamicproxy.BasicAuthCredentials{}
|
cleanedCredentials := []*dynamicproxy.BasicAuthCredentials{}
|
||||||
for _, user := range thisEndpoint.BasicAuthCredentials {
|
for _, user := range thisEndpoint.AuthenticationProvider.BasicAuthCredentials {
|
||||||
cleanedCredentials = append(cleanedCredentials, &dynamicproxy.BasicAuthCredentials{
|
cleanedCredentials = append(cleanedCredentials, &dynamicproxy.BasicAuthCredentials{
|
||||||
Username: user.Username,
|
Username: user.Username,
|
||||||
PasswordHash: "",
|
PasswordHash: "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
thisEndpoint.BasicAuthCredentials = cleanedCredentials
|
thisEndpoint.AuthenticationProvider.BasicAuthCredentials = cleanedCredentials
|
||||||
results = append(results, thisEndpoint)
|
results = append(results, thisEndpoint)
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -1127,7 +1157,7 @@ func HandleCustomHeaderList(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//List all custom headers
|
//List all custom headers
|
||||||
customHeaderList := targetProxyEndpoint.UserDefinedHeaders
|
customHeaderList := targetProxyEndpoint.HeaderRewriteRules.UserDefinedHeaders
|
||||||
if customHeaderList == nil {
|
if customHeaderList == nil {
|
||||||
customHeaderList = []*rewrite.UserDefinedHeader{}
|
customHeaderList = []*rewrite.UserDefinedHeader{}
|
||||||
}
|
}
|
||||||
@ -1269,7 +1299,7 @@ func HandleHostOverwrite(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
//Get the current host header
|
//Get the current host header
|
||||||
js, _ := json.Marshal(targetProxyEndpoint.RequestHostOverwrite)
|
js, _ := json.Marshal(targetProxyEndpoint.HeaderRewriteRules.RequestHostOverwrite)
|
||||||
utils.SendJSONResponse(w, string(js))
|
utils.SendJSONResponse(w, string(js))
|
||||||
} else if r.Method == http.MethodPost {
|
} else if r.Method == http.MethodPost {
|
||||||
//Set the new host header
|
//Set the new host header
|
||||||
@ -1278,7 +1308,7 @@ func HandleHostOverwrite(w http.ResponseWriter, r *http.Request) {
|
|||||||
//As this will require change in the proxy instance we are running
|
//As this will require change in the proxy instance we are running
|
||||||
//we need to clone and respawn this proxy endpoint
|
//we need to clone and respawn this proxy endpoint
|
||||||
newProxyEndpoint := targetProxyEndpoint.Clone()
|
newProxyEndpoint := targetProxyEndpoint.Clone()
|
||||||
newProxyEndpoint.RequestHostOverwrite = newHostname
|
newProxyEndpoint.HeaderRewriteRules.RequestHostOverwrite = newHostname
|
||||||
//Save proxy endpoint
|
//Save proxy endpoint
|
||||||
err = SaveReverseProxyConfig(newProxyEndpoint)
|
err = SaveReverseProxyConfig(newProxyEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1341,7 +1371,7 @@ func HandleHopByHop(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
//Get the current hop by hop header state
|
//Get the current hop by hop header state
|
||||||
js, _ := json.Marshal(!targetProxyEndpoint.DisableHopByHopHeaderRemoval)
|
js, _ := json.Marshal(!targetProxyEndpoint.HeaderRewriteRules.DisableHopByHopHeaderRemoval)
|
||||||
utils.SendJSONResponse(w, string(js))
|
utils.SendJSONResponse(w, string(js))
|
||||||
} else if r.Method == http.MethodPost {
|
} else if r.Method == http.MethodPost {
|
||||||
//Set the hop by hop header state
|
//Set the hop by hop header state
|
||||||
@ -1351,7 +1381,7 @@ func HandleHopByHop(w http.ResponseWriter, r *http.Request) {
|
|||||||
//we need to clone and respawn this proxy endpoint
|
//we need to clone and respawn this proxy endpoint
|
||||||
newProxyEndpoint := targetProxyEndpoint.Clone()
|
newProxyEndpoint := targetProxyEndpoint.Clone()
|
||||||
//Storage file use false as default, so disable removal = not enable remover
|
//Storage file use false as default, so disable removal = not enable remover
|
||||||
newProxyEndpoint.DisableHopByHopHeaderRemoval = !enableHopByHopRemover
|
newProxyEndpoint.HeaderRewriteRules.DisableHopByHopHeaderRemoval = !enableHopByHopRemover
|
||||||
|
|
||||||
//Save proxy endpoint
|
//Save proxy endpoint
|
||||||
err = SaveReverseProxyConfig(newProxyEndpoint)
|
err = SaveReverseProxyConfig(newProxyEndpoint)
|
||||||
@ -1414,7 +1444,7 @@ func HandleHSTSState(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
//Return current HSTS enable state
|
//Return current HSTS enable state
|
||||||
hstsAge := targetProxyEndpoint.HSTSMaxAge
|
hstsAge := targetProxyEndpoint.HeaderRewriteRules.HSTSMaxAge
|
||||||
js, _ := json.Marshal(hstsAge)
|
js, _ := json.Marshal(hstsAge)
|
||||||
utils.SendJSONResponse(w, string(js))
|
utils.SendJSONResponse(w, string(js))
|
||||||
return
|
return
|
||||||
@ -1426,7 +1456,7 @@ func HandleHSTSState(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if newMaxAge == 0 || newMaxAge >= 31536000 {
|
if newMaxAge == 0 || newMaxAge >= 31536000 {
|
||||||
targetProxyEndpoint.HSTSMaxAge = int64(newMaxAge)
|
targetProxyEndpoint.HeaderRewriteRules.HSTSMaxAge = int64(newMaxAge)
|
||||||
err = SaveReverseProxyConfig(targetProxyEndpoint)
|
err = SaveReverseProxyConfig(targetProxyEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.SendErrorResponse(w, "save HSTS state failed: "+err.Error())
|
utils.SendErrorResponse(w, "save HSTS state failed: "+err.Error())
|
||||||
@ -1468,11 +1498,11 @@ func HandlePermissionPolicy(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentPolicy := permissionpolicy.GetDefaultPermissionPolicy()
|
currentPolicy := permissionpolicy.GetDefaultPermissionPolicy()
|
||||||
if targetProxyEndpoint.PermissionPolicy != nil {
|
if targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy != nil {
|
||||||
currentPolicy = targetProxyEndpoint.PermissionPolicy
|
currentPolicy = targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy
|
||||||
}
|
}
|
||||||
result := CurrentPolicyState{
|
result := CurrentPolicyState{
|
||||||
PPEnabled: targetProxyEndpoint.EnablePermissionPolicyHeader,
|
PPEnabled: targetProxyEndpoint.HeaderRewriteRules.EnablePermissionPolicyHeader,
|
||||||
CurrentPolicy: currentPolicy,
|
CurrentPolicy: currentPolicy,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1487,7 +1517,7 @@ func HandlePermissionPolicy(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
targetProxyEndpoint.EnablePermissionPolicyHeader = enableState
|
targetProxyEndpoint.HeaderRewriteRules.EnablePermissionPolicyHeader = enableState
|
||||||
SaveReverseProxyConfig(targetProxyEndpoint)
|
SaveReverseProxyConfig(targetProxyEndpoint)
|
||||||
targetProxyEndpoint.UpdateToRuntime()
|
targetProxyEndpoint.UpdateToRuntime()
|
||||||
utils.SendOK(w)
|
utils.SendOK(w)
|
||||||
@ -1509,7 +1539,7 @@ func HandlePermissionPolicy(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Save it to file
|
//Save it to file
|
||||||
targetProxyEndpoint.PermissionPolicy = newPermissionPolicy
|
targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy = newPermissionPolicy
|
||||||
SaveReverseProxyConfig(targetProxyEndpoint)
|
SaveReverseProxyConfig(targetProxyEndpoint)
|
||||||
targetProxyEndpoint.UpdateToRuntime()
|
targetProxyEndpoint.UpdateToRuntime()
|
||||||
utils.SendOK(w)
|
utils.SendOK(w)
|
||||||
|
43
src/start.go
43
src/start.go
@ -331,6 +331,7 @@ func startupSequence() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Finalize Startup Sequence */
|
||||||
// This sequence start after everything is initialized
|
// This sequence start after everything is initialized
|
||||||
func finalSequence() {
|
func finalSequence() {
|
||||||
//Start ACME renew agent
|
//Start ACME renew agent
|
||||||
@ -339,3 +340,45 @@ func finalSequence() {
|
|||||||
//Inject routing rules
|
//Inject routing rules
|
||||||
registerBuildInRoutingRules()
|
registerBuildInRoutingRules()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shutdown Sequence */
|
||||||
|
func ShutdownSeq() {
|
||||||
|
SystemWideLogger.Println("Shutting down " + SYSTEM_NAME)
|
||||||
|
SystemWideLogger.Println("Closing Netstats Listener")
|
||||||
|
if netstatBuffers != nil {
|
||||||
|
netstatBuffers.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemWideLogger.Println("Closing Statistic Collector")
|
||||||
|
if statisticCollector != nil {
|
||||||
|
statisticCollector.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if mdnsTickerStop != nil {
|
||||||
|
SystemWideLogger.Println("Stopping mDNS Discoverer (might take a few minutes)")
|
||||||
|
// Stop the mdns service
|
||||||
|
mdnsTickerStop <- true
|
||||||
|
}
|
||||||
|
if mdnsScanner != nil {
|
||||||
|
mdnsScanner.Close()
|
||||||
|
}
|
||||||
|
SystemWideLogger.Println("Shutting down load balancer")
|
||||||
|
if loadBalancer != nil {
|
||||||
|
loadBalancer.Close()
|
||||||
|
}
|
||||||
|
SystemWideLogger.Println("Closing Certificates Auto Renewer")
|
||||||
|
if acmeAutoRenewer != nil {
|
||||||
|
acmeAutoRenewer.Close()
|
||||||
|
}
|
||||||
|
//Remove the tmp folder
|
||||||
|
SystemWideLogger.Println("Cleaning up tmp files")
|
||||||
|
os.RemoveAll("./tmp")
|
||||||
|
|
||||||
|
//Close database
|
||||||
|
SystemWideLogger.Println("Stopping system database")
|
||||||
|
sysdb.Close()
|
||||||
|
|
||||||
|
//Close logger
|
||||||
|
SystemWideLogger.Println("Closing system wide logger")
|
||||||
|
SystemWideLogger.Close()
|
||||||
|
}
|
||||||
|
@ -125,10 +125,10 @@
|
|||||||
</td>
|
</td>
|
||||||
<td data-label="" editable="true" datatype="vdir">${vdList}</td>
|
<td data-label="" editable="true" datatype="vdir">${vdList}</td>
|
||||||
<td data-label="" editable="true" datatype="advanced" style="width: 350px;">
|
<td data-label="" editable="true" datatype="advanced" style="width: 350px;">
|
||||||
${subd.RequireBasicAuth?`<i class="ui green check icon"></i> Basic Auth`:``}
|
${subd.AuthenticationProvider.AuthMethod == 0x1?`<i class="ui green check icon"></i> Basic Auth`:``}
|
||||||
${subd.RequireBasicAuth && subd.RequireRateLimit?"<br>":""}
|
${subd.AuthenticationProvider.AuthMethod == 0x1 && subd.RequireRateLimit?"<br>":""}
|
||||||
${subd.RequireRateLimit?`<i class="ui green check icon"></i> Rate Limit @ ${subd.RateLimit} req/s`:``}
|
${subd.AuthenticationProvider.RequireRateLimit?`<i class="ui green check icon"></i> Rate Limit @ ${subd.RateLimit} req/s`:``}
|
||||||
${!subd.RequireBasicAuth && !subd.RequireRateLimit?`<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Special Settings</small>`:""}
|
${!subd.AuthenticationProvider.AuthMethod == 0x1 && !subd.RequireRateLimit?`<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Special Settings</small>`:""}
|
||||||
</td>
|
</td>
|
||||||
<td class="center aligned ignoremw" editable="true" datatype="action" data-label="">
|
<td class="center aligned ignoremw" editable="true" datatype="action" data-label="">
|
||||||
<div class="ui toggle tiny fitted checkbox" style="margin-bottom: -0.5em; margin-right: 0.4em;" title="Enable / Disable Rule">
|
<div class="ui toggle tiny fitted checkbox" style="margin-bottom: -0.5em; margin-right: 0.4em;" title="Enable / Disable Rule">
|
||||||
@ -269,7 +269,7 @@
|
|||||||
</button>`);
|
</button>`);
|
||||||
|
|
||||||
}else if (datatype == "advanced"){
|
}else if (datatype == "advanced"){
|
||||||
let requireBasicAuth = payload.RequireBasicAuth;
|
let requireBasicAuth = payload.AuthenticationProvider.AuthMethod == 0x1;
|
||||||
let basicAuthCheckstate = "";
|
let basicAuthCheckstate = "";
|
||||||
if (requireBasicAuth){
|
if (requireBasicAuth){
|
||||||
basicAuthCheckstate = "checked";
|
basicAuthCheckstate = "checked";
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
<style>
|
||||||
|
#redirect.disabled{
|
||||||
|
opacity: 0.7;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<div class="ui stackable grid">
|
<div class="ui stackable grid">
|
||||||
<div class="ten wide column serverstatusWrapper">
|
<div class="ten wide column serverstatusWrapper">
|
||||||
<div id="serverstatus" class="ui statustab inverted segment">
|
<div id="serverstatus" class="ui statustab inverted segment">
|
||||||
@ -362,9 +369,11 @@
|
|||||||
}
|
}
|
||||||
if (enabled){
|
if (enabled){
|
||||||
//$("#redirect").show();
|
//$("#redirect").show();
|
||||||
|
$("#redirect").removeClass("disabled");
|
||||||
msgbox("Port 80 listener enabled");
|
msgbox("Port 80 listener enabled");
|
||||||
}else{
|
}else{
|
||||||
//$("#redirect").hide();
|
//$("#redirect").hide();
|
||||||
|
$("#redirect").addClass("disabled");
|
||||||
msgbox("Port 80 listener disabled");
|
msgbox("Port 80 listener disabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -402,9 +411,11 @@
|
|||||||
$.get("/api/proxy/listenPort80", function(data){
|
$.get("/api/proxy/listenPort80", function(data){
|
||||||
if (data){
|
if (data){
|
||||||
$("#listenP80").checkbox("set checked");
|
$("#listenP80").checkbox("set checked");
|
||||||
|
$("#redirect").removeClass("disabled");
|
||||||
//$("#redirect").show();
|
//$("#redirect").show();
|
||||||
}else{
|
}else{
|
||||||
$("#listenP80").checkbox("set unchecked");
|
$("#listenP80").checkbox("set unchecked");
|
||||||
|
$("#redirect").addClass("disabled");
|
||||||
//$("#redirect").hide();
|
//$("#redirect").hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Ta
|
|||||||
|
|
||||||
UptimeTargets := []*uptime.Target{}
|
UptimeTargets := []*uptime.Target{}
|
||||||
for hostid, target := range hosts {
|
for hostid, target := range hosts {
|
||||||
if target.Disabled {
|
if target.Disabled || target.DisableUptimeMonitor {
|
||||||
//Skip those proxy rules that is disabled
|
//Skip those proxy rules that is disabled
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user