From 1d4c275db3ef292c1892a6ba03b21548b65c08eb Mon Sep 17 00:00:00 2001 From: Toby Chui Date: Sun, 29 Dec 2024 16:11:00 +0800 Subject: [PATCH] Fixed nil pointer exception in new setups --- src/config.go | 42 ++++++-------- src/mod/dynamicproxy/default.go | 64 +++++++++++++++++++++ src/mod/dynamicproxy/dynamicproxy.go | 10 +++- src/mod/dynamicproxy/endpoints.go | 15 ++++- src/mod/dynamicproxy/proxyRequestHandler.go | 33 ++++++----- src/reverseproxy.go | 6 +- 6 files changed, 123 insertions(+), 47 deletions(-) create mode 100644 src/mod/dynamicproxy/default.go diff --git a/src/config.go b/src/config.go index 365e154..cf67d06 100644 --- a/src/config.go +++ b/src/config.go @@ -48,7 +48,7 @@ func LoadReverseProxyConfig(configFilepath string) error { } //Parse it into dynamic proxy endpoint - thisConfigEndpoint := dynamicproxy.ProxyEndpoint{} + thisConfigEndpoint := dynamicproxy.GetDefaultProxyEndpoint() err = json.Unmarshal(endpointConfig, &thisConfigEndpoint) if err != nil { return err @@ -129,31 +129,23 @@ func RemoveReverseProxyConfig(endpoint string) error { // 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) func GetDefaultRootConfig() (*dynamicproxy.ProxyEndpoint, error) { - //Default Authentication Provider - defaultAuth := &dynamicproxy.AuthenticationProvider{ - AuthMethod: dynamicproxy.AuthMethodNone, - BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{}, - BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{}, - } - //Default settings - rootProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&dynamicproxy.ProxyEndpoint{ - ProxyType: dynamicproxy.ProxyTypeRoot, - RootOrMatchingDomain: "/", - ActiveOrigins: []*loadbalance.Upstream{ - { - OriginIpOrDomain: "127.0.0.1:" + staticWebServer.GetListeningPort(), - RequireTLS: false, - SkipCertValidations: false, - Weight: 0, - }, + //Get the default proxy endpoint + rootProxyEndpointConfig := dynamicproxy.GetDefaultProxyEndpoint() + rootProxyEndpointConfig.ProxyType = dynamicproxy.ProxyTypeRoot + rootProxyEndpointConfig.RootOrMatchingDomain = "/" + rootProxyEndpointConfig.ActiveOrigins = []*loadbalance.Upstream{ + { + OriginIpOrDomain: "127.0.0.1:" + staticWebServer.GetListeningPort(), + RequireTLS: false, + SkipCertValidations: false, + Weight: 0, }, - InactiveOrigins: []*loadbalance.Upstream{}, - BypassGlobalTLS: false, - VirtualDirectories: []*dynamicproxy.VirtualDirectoryEndpoint{}, - AuthenticationProvider: defaultAuth, - DefaultSiteOption: dynamicproxy.DefaultSite_InternalStaticWebServer, - DefaultSiteValue: "", - }) + } + rootProxyEndpointConfig.DefaultSiteOption = dynamicproxy.DefaultSite_InternalStaticWebServer + rootProxyEndpointConfig.DefaultSiteValue = "" + + //Default settings + rootProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&rootProxyEndpointConfig) if err != nil { return nil, err } diff --git a/src/mod/dynamicproxy/default.go b/src/mod/dynamicproxy/default.go new file mode 100644 index 0000000..c7966ef --- /dev/null +++ b/src/mod/dynamicproxy/default.go @@ -0,0 +1,64 @@ +package dynamicproxy + +import ( + "github.com/google/uuid" + "imuslab.com/zoraxy/mod/dynamicproxy/loadbalance" + "imuslab.com/zoraxy/mod/dynamicproxy/rewrite" +) + +/* + Default Provider + + This script provide the default options for all datatype + provided by dynamicproxy module + +*/ + +// GetDefaultAuthenticationProvider return a default authentication provider +func GetDefaultAuthenticationProvider() *AuthenticationProvider { + return &AuthenticationProvider{ + AuthMethod: AuthMethodNone, + BasicAuthCredentials: []*BasicAuthCredentials{}, + BasicAuthExceptionRules: []*BasicAuthExceptionRule{}, + BasicAuthGroupIDs: []string{}, + AutheliaURL: "", + UseHTTPS: false, + } +} + +// GetDefaultHeaderRewriteRules return a default header rewrite rules +func GetDefaultHeaderRewriteRules() *HeaderRewriteRules { + return &HeaderRewriteRules{ + UserDefinedHeaders: []*rewrite.UserDefinedHeader{}, + RequestHostOverwrite: "", + HSTSMaxAge: 0, + EnablePermissionPolicyHeader: false, + PermissionPolicy: nil, + DisableHopByHopHeaderRemoval: false, + } +} + +// GetDefaultProxyEndpoint return a default proxy endpoint +func GetDefaultProxyEndpoint() ProxyEndpoint { + randomPrefix := uuid.New().String() + return ProxyEndpoint{ + ProxyType: ProxyTypeHost, + RootOrMatchingDomain: randomPrefix + ".internal", + MatchingDomainAlias: []string{}, + ActiveOrigins: []*loadbalance.Upstream{}, + InactiveOrigins: []*loadbalance.Upstream{}, + UseStickySession: false, + UseActiveLoadBalance: false, + Disabled: false, + BypassGlobalTLS: false, + VirtualDirectories: []*VirtualDirectoryEndpoint{}, + HeaderRewriteRules: GetDefaultHeaderRewriteRules(), + AuthenticationProvider: GetDefaultAuthenticationProvider(), + RequireRateLimit: false, + RateLimit: 0, + DisableUptimeMonitor: false, + AccessFilterUUID: "default", + DefaultSiteOption: DefaultSite_InternalStaticWebServer, + DefaultSiteValue: "", + } +} diff --git a/src/mod/dynamicproxy/dynamicproxy.go b/src/mod/dynamicproxy/dynamicproxy.go index ce75e41..773910d 100644 --- a/src/mod/dynamicproxy/dynamicproxy.go +++ b/src/mod/dynamicproxy/dynamicproxy.go @@ -157,12 +157,18 @@ func (router *Router) StartProxyService() error { router.Option.Logger.PrintAndLog("dprouter", "failed to get upstream for hostname", err) router.logRequest(r, false, 404, "vdir-http", r.Host) } + + endpointProxyRewriteRules := GetDefaultHeaderRewriteRules() + if sep.HeaderRewriteRules != nil { + endpointProxyRewriteRules = sep.HeaderRewriteRules + } + selectedUpstream.ServeHTTP(w, r, &dpcore.ResponseRewriteRuleSet{ ProxyDomain: selectedUpstream.OriginIpOrDomain, OriginalHost: originalHostHeader, UseTLS: selectedUpstream.RequireTLS, - HostHeaderOverwrite: sep.HeaderRewriteRules.RequestHostOverwrite, - NoRemoveHopByHop: sep.HeaderRewriteRules.DisableHopByHopHeaderRemoval, + HostHeaderOverwrite: endpointProxyRewriteRules.RequestHostOverwrite, + NoRemoveHopByHop: endpointProxyRewriteRules.DisableHopByHopHeaderRemoval, PathPrefix: "", Version: sep.parent.Option.HostVersion, }) diff --git a/src/mod/dynamicproxy/endpoints.go b/src/mod/dynamicproxy/endpoints.go index dd1ef07..62c5535 100644 --- a/src/mod/dynamicproxy/endpoints.go +++ b/src/mod/dynamicproxy/endpoints.go @@ -27,7 +27,12 @@ import ( // Check if a user define header exists in this endpoint, ignore case func (ep *ProxyEndpoint) UserDefinedHeaderExists(key string) bool { - for _, header := range ep.HeaderRewriteRules.UserDefinedHeaders { + endpointProxyRewriteRules := GetDefaultHeaderRewriteRules() + if ep.HeaderRewriteRules != nil { + endpointProxyRewriteRules = ep.HeaderRewriteRules + } + + for _, header := range endpointProxyRewriteRules.UserDefinedHeaders { if strings.EqualFold(header.Key, key) { return true } @@ -38,6 +43,9 @@ func (ep *ProxyEndpoint) UserDefinedHeaderExists(key string) bool { // Remvoe a user defined header from the list func (ep *ProxyEndpoint) RemoveUserDefinedHeader(key string) error { newHeaderList := []*rewrite.UserDefinedHeader{} + if ep.HeaderRewriteRules == nil { + ep.HeaderRewriteRules = GetDefaultHeaderRewriteRules() + } for _, header := range ep.HeaderRewriteRules.UserDefinedHeaders { if !strings.EqualFold(header.Key, key) { newHeaderList = append(newHeaderList, header) @@ -55,6 +63,9 @@ func (ep *ProxyEndpoint) AddUserDefinedHeader(newHeaderRule *rewrite.UserDefined ep.RemoveUserDefinedHeader(newHeaderRule.Key) } + if ep.HeaderRewriteRules == nil { + ep.HeaderRewriteRules = GetDefaultHeaderRewriteRules() + } newHeaderRule.Key = cases.Title(language.Und, cases.NoLower).String(newHeaderRule.Key) ep.HeaderRewriteRules.UserDefinedHeaders = append(ep.HeaderRewriteRules.UserDefinedHeaders, newHeaderRule) return nil @@ -106,7 +117,7 @@ func (ep *ProxyEndpoint) RemoveVirtualDirectoryRuleByMatchingPath(matchingPath s return errors.New("target virtual directory routing rule not found") } -// Delete a vdir rule by its matching path +// Add a vdir rule by its matching path func (ep *ProxyEndpoint) AddVirtualDirectoryRule(vdir *VirtualDirectoryEndpoint) (*ProxyEndpoint, error) { //Check for matching path duplicate if ep.GetVirtualDirectoryRuleByMatchingPath(vdir.MatchingPath) != nil { diff --git a/src/mod/dynamicproxy/proxyRequestHandler.go b/src/mod/dynamicproxy/proxyRequestHandler.go index fefb1af..60f5890 100644 --- a/src/mod/dynamicproxy/proxyRequestHandler.go +++ b/src/mod/dynamicproxy/proxyRequestHandler.go @@ -145,6 +145,10 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe } h.Parent.logRequest(r, true, 101, "host-websocket", selectedUpstream.OriginIpOrDomain) + if target.HeaderRewriteRules == nil { + target.HeaderRewriteRules = GetDefaultHeaderRewriteRules() + } + wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{ SkipTLSValidation: selectedUpstream.SkipCertValidations, SkipOriginCheck: selectedUpstream.SkipWebSocketOriginCheck, @@ -165,18 +169,19 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe } //Populate the user-defined headers with the values from the request - rewrittenUserDefinedHeaders := []*rewrite.UserDefinedHeader{} + headerRewriteOptions := GetDefaultHeaderRewriteRules() if target.HeaderRewriteRules != nil { - rewrittenUserDefinedHeaders = rewrite.PopulateRequestHeaderVariables(r, target.HeaderRewriteRules.UserDefinedHeaders) + headerRewriteOptions = target.HeaderRewriteRules } + rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, headerRewriteOptions.UserDefinedHeaders) //Build downstream and upstream header rules upstreamHeaders, downstreamHeaders := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{ UserDefinedHeaders: rewrittenUserDefinedHeaders, - HSTSMaxAge: target.HeaderRewriteRules.HSTSMaxAge, + HSTSMaxAge: headerRewriteOptions.HSTSMaxAge, HSTSIncludeSubdomains: target.ContainsWildcardName(true), - EnablePermissionPolicyHeader: target.HeaderRewriteRules.EnablePermissionPolicyHeader, - PermissionPolicy: target.HeaderRewriteRules.PermissionPolicy, + EnablePermissionPolicyHeader: headerRewriteOptions.EnablePermissionPolicyHeader, + PermissionPolicy: headerRewriteOptions.PermissionPolicy, }) //Handle the request reverse proxy @@ -188,8 +193,8 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe PathPrefix: "", UpstreamHeaders: upstreamHeaders, DownstreamHeaders: downstreamHeaders, - HostHeaderOverwrite: target.HeaderRewriteRules.RequestHostOverwrite, - NoRemoveHopByHop: target.HeaderRewriteRules.DisableHopByHopHeaderRemoval, + HostHeaderOverwrite: headerRewriteOptions.RequestHostOverwrite, + NoRemoveHopByHop: headerRewriteOptions.DisableHopByHopHeaderRemoval, Version: target.parent.Option.HostVersion, }) @@ -248,18 +253,20 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe } //Populate the user-defined headers with the values from the request - rewrittenUserDefinedHeaders := []*rewrite.UserDefinedHeader{} + headerRewriteOptions := GetDefaultHeaderRewriteRules() if target.parent.HeaderRewriteRules != nil { - rewrittenUserDefinedHeaders = rewrite.PopulateRequestHeaderVariables(r, target.parent.HeaderRewriteRules.UserDefinedHeaders) + headerRewriteOptions = target.parent.HeaderRewriteRules } + rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, headerRewriteOptions.UserDefinedHeaders) + //Build downstream and upstream header rules, use the parent (subdomain) endpoint's headers upstreamHeaders, downstreamHeaders := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{ UserDefinedHeaders: rewrittenUserDefinedHeaders, - HSTSMaxAge: target.parent.HeaderRewriteRules.HSTSMaxAge, + HSTSMaxAge: headerRewriteOptions.HSTSMaxAge, HSTSIncludeSubdomains: target.parent.ContainsWildcardName(true), - EnablePermissionPolicyHeader: target.parent.HeaderRewriteRules.EnablePermissionPolicyHeader, - PermissionPolicy: target.parent.HeaderRewriteRules.PermissionPolicy, + EnablePermissionPolicyHeader: headerRewriteOptions.EnablePermissionPolicyHeader, + PermissionPolicy: headerRewriteOptions.PermissionPolicy, }) //Handle the virtual directory reverse proxy request @@ -270,7 +277,7 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe PathPrefix: target.MatchingPath, UpstreamHeaders: upstreamHeaders, DownstreamHeaders: downstreamHeaders, - HostHeaderOverwrite: target.parent.HeaderRewriteRules.RequestHostOverwrite, + HostHeaderOverwrite: headerRewriteOptions.RequestHostOverwrite, Version: target.parent.parent.Option.HostVersion, }) diff --git a/src/reverseproxy.go b/src/reverseproxy.go index 28c80aa..cde2328 100644 --- a/src/reverseproxy.go +++ b/src/reverseproxy.go @@ -320,10 +320,6 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) { BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{}, } - thisCustomHeaderRules := dynamicproxy.HeaderRewriteRules{ - UserDefinedHeaders: []*rewrite.UserDefinedHeader{}, - } - //Generate a proxy endpoint object thisProxyEndpoint := dynamicproxy.ProxyEndpoint{ //I/O @@ -353,7 +349,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) { AuthenticationProvider: &thisAuthenticationProvider, //Header Rewrite - HeaderRewriteRules: &thisCustomHeaderRules, + HeaderRewriteRules: dynamicproxy.GetDefaultHeaderRewriteRules(), //Default Site DefaultSiteOption: 0,