From 52d3b2f8c242481d7ba0628ff00870001a8ce611 Mon Sep 17 00:00:00 2001 From: Toby Chui Date: Wed, 26 Jul 2023 19:17:43 +0800 Subject: [PATCH] Fixed memory leaking + Patch on memory leaking for Windows netstat module (do not effect any of the previous non Windows builds) + Fixed potential memory leak in acme handler logic + Added "do you want to get a TLS certificate for this subdomain?" dialog when a new subdomain proxy rule is created --- src/acme.go | 1 + src/api.go | 4 ++ src/geoip.go | 39 ---------- src/main.go | 2 +- src/mod/dynamicproxy/dpcore/dpcore.go | 4 -- src/mod/dynamicproxy/proxyRequestHandler.go | 1 - src/mod/netstat/netstat.go | 13 ++-- src/mod/uptime/uptime.go | 8 +-- src/mod/utils/utils.go | 14 ---- src/start.go | 3 +- src/web/components/access.html | 4 +- src/web/components/rules.html | 79 ++++++++++++++++++++- src/web/main.css | 2 +- src/web/snippet/acme.html | 4 +- 14 files changed, 101 insertions(+), 77 deletions(-) delete mode 100644 src/geoip.go diff --git a/src/acme.go b/src/acme.go index dc44039..72e5883 100644 --- a/src/acme.go +++ b/src/acme.go @@ -66,6 +66,7 @@ func acmeRegisterSpecialRoutingRule() { } resBody, err := ioutil.ReadAll(res.Body) + defer res.Body.Close() if err != nil { fmt.Printf("error reading: %s\n", err) return diff --git a/src/api.go b/src/api.go index 77ba527..d52b937 100644 --- a/src/api.go +++ b/src/api.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "net/http" + "net/http/pprof" "imuslab.com/zoraxy/mod/acme/acmewizard" "imuslab.com/zoraxy/mod/auth" @@ -166,6 +167,9 @@ func initAPIs() { http.HandleFunc("/api/conf/export", ExportConfigAsZip) http.HandleFunc("/api/conf/import", ImportConfigFromZip) + //Debug + authRouter.HandleFunc("/api/info/pprof", pprof.Index) + //If you got APIs to add, append them here } diff --git a/src/geoip.go b/src/geoip.go deleted file mode 100644 index ed3f0bd..0000000 --- a/src/geoip.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "net" - "net/http" - "strings" - - "github.com/oschwald/geoip2-golang" -) - -func getCountryCodeFromRequest(r *http.Request) string { - countryCode := "" - - // Get the IP address of the user from the request headers - ipAddress := r.Header.Get("X-Forwarded-For") - if ipAddress == "" { - ipAddress = strings.Split(r.RemoteAddr, ":")[0] - } - - // Open the GeoIP database - db, err := geoip2.Open("./tmp/GeoIP2-Country.mmdb") - if err != nil { - // Handle the error - return countryCode - } - defer db.Close() - - // Look up the country code for the IP address - record, err := db.Country(net.ParseIP(ipAddress)) - if err != nil { - // Handle the error - return countryCode - } - - // Get the ISO country code from the record - countryCode = record.Country.IsoCode - - return countryCode -} diff --git a/src/main.go b/src/main.go index 05bb2ef..8bbac8d 100644 --- a/src/main.go +++ b/src/main.go @@ -41,7 +41,7 @@ var ztAPIPort = flag.Int("ztport", 9993, "ZeroTier controller API port") var acmeAutoRenewInterval = flag.Int("autorenew", 86400, "ACME auto TLS/SSL certificate renew check interval (seconds)") var ( name = "Zoraxy" - version = "2.6.5" + version = "2.6.6" nodeUUID = "generic" development = false //Set this to false to use embedded web fs bootTime = time.Now().Unix() diff --git a/src/mod/dynamicproxy/dpcore/dpcore.go b/src/mod/dynamicproxy/dpcore/dpcore.go index 830d2e8..1b1b11a 100644 --- a/src/mod/dynamicproxy/dpcore/dpcore.go +++ b/src/mod/dynamicproxy/dpcore/dpcore.go @@ -14,10 +14,6 @@ import ( var onExitFlushLoop func() -const ( - defaultTimeout = time.Minute * 5 -) - // ReverseProxy is an HTTP Handler that takes an incoming request and // sends it to another server, proxying the response back to the // client, support http, also support https tunnel using http.hijacker diff --git a/src/mod/dynamicproxy/proxyRequestHandler.go b/src/mod/dynamicproxy/proxyRequestHandler.go index 6a10ff7..01d2858 100644 --- a/src/mod/dynamicproxy/proxyRequestHandler.go +++ b/src/mod/dynamicproxy/proxyRequestHandler.go @@ -183,6 +183,5 @@ func (h *ProxyHandler) logRequest(r *http.Request, succ bool, statusCode int, fo } h.Parent.Option.StatisticCollector.RecordRequest(requestInfo) }() - } } diff --git a/src/mod/netstat/netstat.go b/src/mod/netstat/netstat.go index d784bce..55dc6e3 100644 --- a/src/mod/netstat/netstat.go +++ b/src/mod/netstat/netstat.go @@ -213,6 +213,7 @@ func GetNetworkInterfaceStats() (int64, int64, error) { out, err := cmd.Output() if err != nil { callbackChan <- wmicResult{0, 0, err} + return } //Filter out the first line @@ -251,18 +252,16 @@ func GetNetworkInterfaceStats() (int64, int64, error) { go func() { //Spawn a timer to terminate the cmd process if timeout - var timer *time.Timer - timer = time.AfterFunc(3*time.Second, func() { - timer.Stop() - if cmd != nil && cmd.Process != nil { - cmd.Process.Kill() - } + time.Sleep(3 * time.Second) + if cmd != nil && cmd.Process != nil { + cmd.Process.Kill() callbackChan <- wmicResult{0, 0, errors.New("wmic execution timeout")} - }) + } }() result := wmicResult{} result = <-callbackChan + cmd = nil if result.Err != nil { log.Println("Unable to extract NIC info from wmic: " + result.Err.Error()) } diff --git a/src/mod/uptime/uptime.go b/src/mod/uptime/uptime.go index 725b59d..1308592 100644 --- a/src/mod/uptime/uptime.go +++ b/src/mod/uptime/uptime.go @@ -93,8 +93,6 @@ func (m *Monitor) ExecuteUptimeCheck() { Latency: laterncy, } - //fmt.Println(thisRecord) - } else { log.Println("Unknown protocol: " + target.Protocol + ". Skipping") continue @@ -238,9 +236,11 @@ func getWebsiteStatus(url string) (int, error) { } return 0, err } - + defer resp.Body.Close() + status_code := resp.StatusCode + return status_code, nil } + defer resp.Body.Close() status_code := resp.StatusCode - resp.Body.Close() return status_code, nil } diff --git a/src/mod/utils/utils.go b/src/mod/utils/utils.go index a604113..8315317 100644 --- a/src/mod/utils/utils.go +++ b/src/mod/utils/utils.go @@ -1,10 +1,7 @@ package utils import ( - "bufio" - "encoding/base64" "errors" - "io" "log" "net/http" "os" @@ -131,17 +128,6 @@ func TimeToString(targetTime time.Time) string { return targetTime.Format("2006-01-02 15:04:05") } -func LoadImageAsBase64(filepath string) (string, error) { - if !FileExists(filepath) { - return "", errors.New("File not exists") - } - f, _ := os.Open(filepath) - reader := bufio.NewReader(f) - content, _ := io.ReadAll(reader) - encoded := base64.StdEncoding.EncodeToString(content) - return string(encoded), nil -} - // Use for redirections func ConstructRelativePathFromRequestURL(requestURI string, redirectionLocation string) string { if strings.Count(requestURI, "/") == 1 { diff --git a/src/start.go b/src/start.go index a57119e..30d5eb2 100644 --- a/src/start.go +++ b/src/start.go @@ -128,7 +128,8 @@ func startupSequence() { BuildVersion: version, }, "") if err != nil { - panic(err) + log.Println("Unable to startup mDNS service.") + log.Fatal(err) } //Start initial scanning diff --git a/src/web/components/access.html b/src/web/components/access.html index c7324e8..c4e9785 100644 --- a/src/web/components/access.html +++ b/src/web/components/access.html @@ -308,7 +308,7 @@
IP Address support the following formats
-
Fixed IP Address (e.g. 192.128.4.100)
+
Fixed IP Address (e.g. 192.128.4.100 or fe80::210:5aff:feaa:20a2)
IP Wildcard (e.g. 172.164.*.*)
CIDR String (e.g. 128.32.0.1/16)
@@ -625,7 +625,7 @@
IP Address support the following formats
-
Fixed IP Address (e.g. 192.128.4.100)
+
Fixed IP Address (e.g. 192.128.4.100 or fe80::210:5aff:feaa:20a2)
IP Wildcard (e.g. 172.164.*.*)
CIDR String (e.g. 128.32.0.1/16)
diff --git a/src/web/components/rules.html b/src/web/components/rules.html index 6798e26..b70a6ab 100644 --- a/src/web/components/rules.html +++ b/src/web/components/rules.html @@ -172,13 +172,27 @@ //OK listVdirs(); listSubd(); - msgbox("Proxy Endpoint Added"); + //Clear old data $("#rootname").val(""); $("#proxyDomain").val(""); credentials = []; updateTable(); + + //Check if it is a new subdomain and TLS enabled + if (type == "subd" && $("#tls").checkbox("is checked")){ + confirmBox("Request new SSL Cert for this subdomain?", function(choice){ + if (choice == true){ + //Get a new cert using ACME + msgbox("Requesting certificate via Let's Encrypt..."); + console.log("Trying to get a new certificate via ACME"); + obtainCertificate(rootname); + } + }); + }else{ + msgbox("Proxy Endpoint Added"); + } } } }); @@ -437,4 +451,67 @@ })); showSideWrapper("snippet/basicAuthEditor.html?t=" + Date.now() + "#" + payload); } + + + /* + Obtain Certificate via ACME + */ + + //Load the ACME email from server side + let acmeEmail = ""; + $.get("/api/acme/autoRenew/email", function(data){ + if (data != "" && data != undefined && data != null){ + acmeEmail = data; + } + }); + + // Obtain certificate from API, only support one domain + function obtainCertificate(domains) { + let filename = ""; + let email = acmeEmail; + if (acmeEmail == ""){ + let rootDomain = domains.split(".").pop(); + email = "admin@" + rootDomain; + } + if (filename.trim() == "" && !domains.includes(",")){ + //Zoraxy filename are the matching name for domains. + //Use the same as domains + filename = domains; + }else if (filename != "" && !domains.includes(",")){ + //Invalid settings. Force the filename to be same as domain + //if there are only 1 domain + filename = domains; + }else{ + parent.msgbox("Filename cannot be empty for certs containing multiple domains.") + return; + } + + $.ajax({ + url: "/api/acme/obtainCert", + method: "GET", + data: { + domains: domains, + filename: filename, + email: email, + ca: "Let's Encrypt", + }, + success: function(response) { + if (response.error) { + console.log("Error:", response.error); + // Show error message + msgbox(response.error, false, 12000); + } else { + console.log("Certificate installed successfully"); + // Show success message + msgbox("Certificate installed successfully"); + + // Renew the parent certificate list + initManagedDomainCertificateList(); + } + }, + error: function(error) { + console.log("Failed to install certificate:", error); + } + }); + } \ No newline at end of file diff --git a/src/web/main.css b/src/web/main.css index acddb86..c0d0416 100644 --- a/src/web/main.css +++ b/src/web/main.css @@ -116,7 +116,7 @@ body{ } #confirmBox .ui.progress .bar{ - background: #ffe32b !important; + background: #a9d1f3 !important; } #confirmBox .confirmBoxBody .button{ diff --git a/src/web/snippet/acme.html b/src/web/snippet/acme.html index 4c05009..eff049e 100644 --- a/src/web/snippet/acme.html +++ b/src/web/snippet/acme.html @@ -83,8 +83,8 @@
-

Manual Renew

-

Pick a certificate below to force renew

+

Generate New Certificate

+

Enter a new / existing domain(s) to request new certificate(s)