package dynamicproxy import ( "errors" "log" "net/url" "strings" "time" "imuslab.com/zoraxy/mod/dynamicproxy/dpcore" "imuslab.com/zoraxy/mod/utils" ) /* Dynamic Proxy Router Functions This script handle the proxy rules router spawning and preparation */ // Prepare proxy route generate a proxy handler service object for your endpoint func (router *Router) PrepareProxyRoute(endpoint *ProxyEndpoint) (*ProxyEndpoint, error) { for _, thisOrigin := range endpoint.ActiveOrigins { //Create the proxy routing handler err := thisOrigin.StartProxy() if err != nil { log.Println("Unable to setup upstream " + thisOrigin.OriginIpOrDomain + ": " + err.Error()) continue } } endpoint.parent = router //Prepare proxy routing handler for each of the virtual directories for _, vdir := range endpoint.VirtualDirectories { domain := vdir.Domain if len(domain) == 0 { //invalid vdir continue } if domain[len(domain)-1:] == "/" { domain = domain[:len(domain)-1] } //Parse the web proxy endpoint webProxyEndpoint := domain if !strings.HasPrefix("http://", domain) && !strings.HasPrefix("https://", domain) { //TLS is not hardcoded in proxy target domain if vdir.RequireTLS { webProxyEndpoint = "https://" + webProxyEndpoint } else { webProxyEndpoint = "http://" + webProxyEndpoint } } path, err := url.Parse(webProxyEndpoint) if err != nil { return nil, err } proxy := dpcore.NewDynamicProxyCore(path, vdir.MatchingPath, &dpcore.DpcoreOptions{ IgnoreTLSVerification: vdir.SkipCertValidations, FlushInterval: 500 * time.Millisecond, }) vdir.proxy = proxy vdir.parent = endpoint } return endpoint, nil } // Add Proxy Route to current runtime. Call to PrepareProxyRoute before adding to runtime func (router *Router) AddProxyRouteToRuntime(endpoint *ProxyEndpoint) error { lookupHostname := strings.ToLower(endpoint.RootOrMatchingDomain) if len(endpoint.ActiveOrigins) == 0 { //There are no active origins. No need to check for ready router.ProxyEndpoints.Store(lookupHostname, endpoint) return nil } if !router.loadBalancer.UpstreamsReady(endpoint.ActiveOrigins) { //This endpoint is not prepared return errors.New("proxy endpoint not ready. Use PrepareProxyRoute before adding to runtime") } // Push record into running subdomain endpoints router.ProxyEndpoints.Store(lookupHostname, endpoint) return nil } // Set given Proxy Route as Root. Call to PrepareProxyRoute before adding to runtime func (router *Router) SetProxyRouteAsRoot(endpoint *ProxyEndpoint) error { if !router.loadBalancer.UpstreamsReady(endpoint.ActiveOrigins) { //This endpoint is not prepared return errors.New("proxy endpoint not ready. Use PrepareProxyRoute before adding to runtime") } // Push record into running root endpoints router.Root = endpoint return nil } // ProxyEndpoint remove provide global access by key func (router *Router) RemoveProxyEndpointByRootname(rootnameOrMatchingDomain string) error { targetEpt, err := router.LoadProxy(rootnameOrMatchingDomain) if err != nil { return err } return targetEpt.Remove() } // GetProxyEndpointById retrieves a proxy endpoint by its ID from the Router's ProxyEndpoints map. // It returns the ProxyEndpoint if found, or an error if not found. func (h *Router) GetProxyEndpointById(searchingDomain string, includeAlias bool) (*ProxyEndpoint, error) { var found *ProxyEndpoint h.ProxyEndpoints.Range(func(key, value interface{}) bool { proxy, ok := value.(*ProxyEndpoint) if ok && (proxy.RootOrMatchingDomain == searchingDomain || (includeAlias && utils.StringInArray(proxy.MatchingDomainAlias, searchingDomain))) { found = proxy return false // stop iteration } return true // continue iteration }) if found != nil { return found, nil } return nil, errors.New("proxy rule with given id not found") } func (h *Router) GetProxyEndpointByAlias(alias string) (*ProxyEndpoint, error) { var found *ProxyEndpoint h.ProxyEndpoints.Range(func(key, value interface{}) bool { proxy, ok := value.(*ProxyEndpoint) if !ok { return true } //Also check for wildcard aliases that matches the alias for _, thisAlias := range proxy.MatchingDomainAlias { if ok && thisAlias == alias { found = proxy return false // stop iteration } else if ok && strings.HasPrefix(thisAlias, "*") { //Check if the alias matches a wildcard alias if strings.HasSuffix(alias, thisAlias[1:]) { found = proxy return false // stop iteration } } } return true // continue iteration }) if found != nil { return found, nil } return nil, errors.New("proxy rule with given alias not found") }