Merge pull request #84 from tobychui/2.6.8

Update v2.6.8
This commit is contained in:
Toby Chui 2023-11-25 22:25:22 +08:00 committed by GitHub
commit 20cf290d37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 629 additions and 114 deletions

View File

@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"log"
"math/rand" "math/rand"
"net/http" "net/http"
"regexp" "regexp"
@ -29,7 +28,7 @@ func getRandomPort(minPort int) int {
// init the new ACME instance // init the new ACME instance
func initACME() *acme.ACMEHandler { func initACME() *acme.ACMEHandler {
log.Println("Starting ACME handler") SystemWideLogger.Println("Starting ACME handler")
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
// Generate a random port above 30000 // Generate a random port above 30000
port := getRandomPort(30000) port := getRandomPort(30000)
@ -44,7 +43,7 @@ func initACME() *acme.ACMEHandler {
// create the special routing rule for ACME // create the special routing rule for ACME
func acmeRegisterSpecialRoutingRule() { func acmeRegisterSpecialRoutingRule() {
log.Println("Assigned temporary port:" + acmeHandler.Getport()) SystemWideLogger.Println("Assigned temporary port:" + acmeHandler.Getport())
err := dynamicProxyRouter.AddRoutingRules(&dynamicproxy.RoutingRule{ err := dynamicProxyRouter.AddRoutingRules(&dynamicproxy.RoutingRule{
ID: "acme-autorenew", ID: "acme-autorenew",
@ -79,7 +78,7 @@ func acmeRegisterSpecialRoutingRule() {
}) })
if err != nil { if err != nil {
log.Println("[Err] " + err.Error()) SystemWideLogger.PrintAndLog("ACME", "Unable register temp port for DNS resolver", err)
} }
} }
@ -89,7 +88,7 @@ func AcmeCheckAndHandleRenewCertificate(w http.ResponseWriter, r *http.Request)
if dynamicProxyRouter.Option.Port == 443 { if dynamicProxyRouter.Option.Port == 443 {
//Enable port 80 to 443 redirect //Enable port 80 to 443 redirect
if !dynamicProxyRouter.Option.ForceHttpsRedirect { if !dynamicProxyRouter.Option.ForceHttpsRedirect {
log.Println("Temporary enabling HTTP to HTTPS redirect for ACME certificate renew requests") SystemWideLogger.Println("Temporary enabling HTTP to HTTPS redirect for ACME certificate renew requests")
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
} else { } else {
//Set this to true, so after renew, do not turn it off //Set this to true, so after renew, do not turn it off
@ -110,7 +109,7 @@ func AcmeCheckAndHandleRenewCertificate(w http.ResponseWriter, r *http.Request)
if dynamicProxyRouter.Option.Port == 443 { if dynamicProxyRouter.Option.Port == 443 {
if !isForceHttpsRedirectEnabledOriginally { if !isForceHttpsRedirectEnabledOriginally {
//Default is off. Turn the redirection off //Default is off. Turn the redirection off
log.Println("Restoring HTTP to HTTPS redirect settings") SystemWideLogger.PrintAndLog("ACME", "Restoring HTTP to HTTPS redirect settings", nil)
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false)
} }
} }
@ -130,7 +129,7 @@ func HandleACMEPreferredCA(w http.ResponseWriter, r *http.Request) {
acme.IsSupportedCA(ca) acme.IsSupportedCA(ca)
//Set the new config //Set the new config
sysdb.Write("acmepref", "prefca", ca) sysdb.Write("acmepref", "prefca", ca)
log.Println("Updating prefered ACME CA to " + ca) SystemWideLogger.Println("Updating prefered ACME CA to " + ca)
utils.SendOK(w) utils.SendOK(w)
} }

View File

@ -54,6 +54,7 @@ func initAPIs() {
authRouter.HandleFunc("/api/proxy/tlscheck", HandleCheckSiteSupportTLS) authRouter.HandleFunc("/api/proxy/tlscheck", HandleCheckSiteSupportTLS)
authRouter.HandleFunc("/api/proxy/setIncoming", HandleIncomingPortSet) authRouter.HandleFunc("/api/proxy/setIncoming", HandleIncomingPortSet)
authRouter.HandleFunc("/api/proxy/useHttpsRedirect", HandleUpdateHttpsRedirect) authRouter.HandleFunc("/api/proxy/useHttpsRedirect", HandleUpdateHttpsRedirect)
authRouter.HandleFunc("/api/proxy/listenPort80", HandleUpdatePort80Listener)
authRouter.HandleFunc("/api/proxy/requestIsProxied", HandleManagementProxyCheck) authRouter.HandleFunc("/api/proxy/requestIsProxied", HandleManagementProxyCheck)
//Reverse proxy root related APIs //Reverse proxy root related APIs
authRouter.HandleFunc("/api/proxy/root/listOptions", HandleRootRouteOptionList) authRouter.HandleFunc("/api/proxy/root/listOptions", HandleRootRouteOptionList)

View File

@ -6,7 +6,6 @@ import (
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"io" "io"
"log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -128,7 +127,7 @@ func handleListDomains(w http.ResponseWriter, r *http.Request) {
certBtyes, err := os.ReadFile(certFilepath) certBtyes, err := os.ReadFile(certFilepath)
if err != nil { if err != nil {
// Unable to load this file // Unable to load this file
log.Println("Unable to load certificate: " + certFilepath) SystemWideLogger.PrintAndLog("TLS", "Unable to load certificate: "+certFilepath, err)
continue continue
} else { } else {
// Cert loaded. Check its expiry time // Cert loaded. Check its expiry time
@ -182,11 +181,11 @@ func handleToggleTLSProxy(w http.ResponseWriter, r *http.Request) {
} else { } else {
if newState == "true" { if newState == "true" {
sysdb.Write("settings", "usetls", true) sysdb.Write("settings", "usetls", true)
log.Println("Enabling TLS mode on reverse proxy") SystemWideLogger.Println("Enabling TLS mode on reverse proxy")
dynamicProxyRouter.UpdateTLSSetting(true) dynamicProxyRouter.UpdateTLSSetting(true)
} else if newState == "false" { } else if newState == "false" {
sysdb.Write("settings", "usetls", false) sysdb.Write("settings", "usetls", false)
log.Println("Disabling TLS mode on reverse proxy") SystemWideLogger.Println("Disabling TLS mode on reverse proxy")
dynamicProxyRouter.UpdateTLSSetting(false) dynamicProxyRouter.UpdateTLSSetting(false)
} else { } else {
utils.SendErrorResponse(w, "invalid state given. Only support true or false") utils.SendErrorResponse(w, "invalid state given. Only support true or false")
@ -213,11 +212,11 @@ func handleSetTlsRequireLatest(w http.ResponseWriter, r *http.Request) {
} else { } else {
if newState == "true" { if newState == "true" {
sysdb.Write("settings", "forceLatestTLS", true) sysdb.Write("settings", "forceLatestTLS", true)
log.Println("Updating minimum TLS version to v1.2 or above") SystemWideLogger.Println("Updating minimum TLS version to v1.2 or above")
dynamicProxyRouter.UpdateTLSVersion(true) dynamicProxyRouter.UpdateTLSVersion(true)
} else if newState == "false" { } else if newState == "false" {
sysdb.Write("settings", "forceLatestTLS", false) sysdb.Write("settings", "forceLatestTLS", false)
log.Println("Updating minimum TLS version to v1.0 or above") SystemWideLogger.Println("Updating minimum TLS version to v1.0 or above")
dynamicProxyRouter.UpdateTLSVersion(false) dynamicProxyRouter.UpdateTLSVersion(false)
} else { } else {
utils.SendErrorResponse(w, "invalid state given") utils.SendErrorResponse(w, "invalid state given")

View File

@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -29,6 +28,7 @@ type Record struct {
Rootname string Rootname string
ProxyTarget string ProxyTarget string
UseTLS bool UseTLS bool
BypassGlobalTLS bool
SkipTlsValidation bool SkipTlsValidation bool
RequireBasicAuth bool RequireBasicAuth bool
BasicAuthCredentials []*dynamicproxy.BasicAuthCredentials BasicAuthCredentials []*dynamicproxy.BasicAuthCredentials
@ -61,11 +61,11 @@ func SaveReverseProxyEndpointToFile(proxyEndpoint *dynamicproxy.ProxyEndpoint) e
func RemoveReverseProxyConfigFile(rootname string) error { func RemoveReverseProxyConfigFile(rootname string) error {
filename := getFilenameFromRootName(rootname) filename := getFilenameFromRootName(rootname)
removePendingFile := strings.ReplaceAll(filepath.Join("./conf/proxy/", filename), "\\", "/") removePendingFile := strings.ReplaceAll(filepath.Join("./conf/proxy/", filename), "\\", "/")
log.Println("Config Removed: ", removePendingFile) SystemWideLogger.Println("Config Removed: ", removePendingFile)
if utils.FileExists(removePendingFile) { if utils.FileExists(removePendingFile) {
err := os.Remove(removePendingFile) err := os.Remove(removePendingFile)
if err != nil { if err != nil {
log.Println(err.Error()) SystemWideLogger.PrintAndLog("Proxy", "Unabel to remove config file", err)
return err return err
} }
} }
@ -81,6 +81,7 @@ func LoadReverseProxyConfig(filename string) (*Record, error) {
Rootname: "", Rootname: "",
ProxyTarget: "", ProxyTarget: "",
UseTLS: false, UseTLS: false,
BypassGlobalTLS: false,
SkipTlsValidation: false, SkipTlsValidation: false,
RequireBasicAuth: false, RequireBasicAuth: false,
BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{}, BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{},
@ -109,6 +110,7 @@ func ConvertProxyEndpointToRecord(targetProxyEndpoint *dynamicproxy.ProxyEndpoin
Rootname: targetProxyEndpoint.RootOrMatchingDomain, Rootname: targetProxyEndpoint.RootOrMatchingDomain,
ProxyTarget: targetProxyEndpoint.Domain, ProxyTarget: targetProxyEndpoint.Domain,
UseTLS: targetProxyEndpoint.RequireTLS, UseTLS: targetProxyEndpoint.RequireTLS,
BypassGlobalTLS: targetProxyEndpoint.BypassGlobalTLS,
SkipTlsValidation: targetProxyEndpoint.SkipCertValidations, SkipTlsValidation: targetProxyEndpoint.SkipCertValidations,
RequireBasicAuth: targetProxyEndpoint.RequireBasicAuth, RequireBasicAuth: targetProxyEndpoint.RequireBasicAuth,
BasicAuthCredentials: targetProxyEndpoint.BasicAuthCredentials, BasicAuthCredentials: targetProxyEndpoint.BasicAuthCredentials,
@ -191,14 +193,14 @@ func ExportConfigAsZip(w http.ResponseWriter, r *http.Request) {
//Also zip in the sysdb //Also zip in the sysdb
zipFile, err := zipWriter.Create("sys.db") zipFile, err := zipWriter.Create("sys.db")
if err != nil { if err != nil {
log.Println("[Backup] Unable to zip sysdb: " + err.Error()) SystemWideLogger.PrintAndLog("Backup", "Unable to zip sysdb", err)
return return
} }
// Open the file on disk // Open the file on disk
file, err := os.Open("sys.db") file, err := os.Open("sys.db")
if err != nil { if err != nil {
log.Println("[Backup] Unable to open sysdb: " + err.Error()) SystemWideLogger.PrintAndLog("Backup", "Unable to open sysdb", err)
return return
} }
defer file.Close() defer file.Close()
@ -206,7 +208,7 @@ func ExportConfigAsZip(w http.ResponseWriter, r *http.Request) {
// Copy the file contents to the zip file // Copy the file contents to the zip file
_, err = io.Copy(zipFile, file) _, err = io.Copy(zipFile, file)
if err != nil { if err != nil {
log.Println(err) SystemWideLogger.Println(err)
return return
} }
@ -311,12 +313,12 @@ func ImportConfigFromZip(w http.ResponseWriter, r *http.Request) {
// Send a success response // Send a success response
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
log.Println("Configuration restored") SystemWideLogger.Println("Configuration restored")
fmt.Fprintln(w, "Configuration restored") fmt.Fprintln(w, "Configuration restored")
if restoreDatabase { if restoreDatabase {
go func() { go func() {
log.Println("Database altered. Restarting in 3 seconds...") SystemWideLogger.Println("Database altered. Restarting in 3 seconds...")
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
os.Exit(0) os.Exit(0)
}() }()

View File

@ -20,6 +20,7 @@ import (
"imuslab.com/zoraxy/mod/email" "imuslab.com/zoraxy/mod/email"
"imuslab.com/zoraxy/mod/ganserv" "imuslab.com/zoraxy/mod/ganserv"
"imuslab.com/zoraxy/mod/geodb" "imuslab.com/zoraxy/mod/geodb"
"imuslab.com/zoraxy/mod/info/logger"
"imuslab.com/zoraxy/mod/mdns" "imuslab.com/zoraxy/mod/mdns"
"imuslab.com/zoraxy/mod/netstat" "imuslab.com/zoraxy/mod/netstat"
"imuslab.com/zoraxy/mod/pathrule" "imuslab.com/zoraxy/mod/pathrule"
@ -44,10 +45,11 @@ var acmeAutoRenewInterval = flag.Int("autorenew", 86400, "ACME auto TLS/SSL cert
var enableHighSpeedGeoIPLookup = flag.Bool("fastgeoip", false, "Enable high speed geoip lookup, require 1GB extra memory (Not recommend for low end devices)") var enableHighSpeedGeoIPLookup = flag.Bool("fastgeoip", false, "Enable high speed geoip lookup, require 1GB extra memory (Not recommend for low end devices)")
var staticWebServerRoot = flag.String("webroot", "./www", "Static web server root folder. Only allow chnage in start paramters") var staticWebServerRoot = flag.String("webroot", "./www", "Static web server root folder. Only allow chnage in start paramters")
var allowWebFileManager = flag.Bool("webfm", true, "Enable web file manager for static web server root folder") var allowWebFileManager = flag.Bool("webfm", true, "Enable web file manager for static web server root folder")
var logOutputToFile = flag.Bool("log", true, "Log terminal output to file")
var ( var (
name = "Zoraxy" name = "Zoraxy"
version = "2.6.7" version = "2.6.8"
nodeUUID = "generic" nodeUUID = "generic"
development = false //Set this to false to use embedded web fs development = false //Set this to false to use embedded web fs
bootTime = time.Now().Unix() bootTime = time.Now().Unix()
@ -82,6 +84,7 @@ var (
//Helper modules //Helper modules
EmailSender *email.Sender //Email sender that handle email sending EmailSender *email.Sender //Email sender that handle email sending
AnalyticLoader *analytic.DataLoader //Data loader for Zoraxy Analytic AnalyticLoader *analytic.DataLoader //Data loader for Zoraxy Analytic
SystemWideLogger *logger.Logger //Logger for Zoraxy
) )
// Kill signal handler. Do something before the system the core terminate. // Kill signal handler. Do something before the system the core terminate.
@ -116,6 +119,9 @@ func ShutdownSeq() {
fmt.Println("- Cleaning up tmp files") fmt.Println("- Cleaning up tmp files")
os.RemoveAll("./tmp") os.RemoveAll("./tmp")
fmt.Println("- Closing system wide logger")
SystemWideLogger.Close()
//Close database, final //Close database, final
fmt.Println("- Stopping system database") fmt.Println("- Stopping system database")
sysdb.Close() sysdb.Close()
@ -151,7 +157,7 @@ func main() {
} }
uuidBytes, err := os.ReadFile(uuidRecord) uuidBytes, err := os.ReadFile(uuidRecord)
if err != nil { if err != nil {
log.Println("Unable to read system uuid from file system") SystemWideLogger.PrintAndLog("ZeroTier", "Unable to read system uuid from file system", nil)
panic(err) panic(err)
} }
nodeUUID = string(uuidBytes) nodeUUID = string(uuidBytes)
@ -173,7 +179,7 @@ func main() {
//Start the finalize sequences //Start the finalize sequences
finalSequence() finalSequence()
log.Println("Zoraxy started. Visit control panel at http://localhost" + handler.Port) SystemWideLogger.Println("Zoraxy started. Visit control panel at http://localhost" + handler.Port)
err = http.ListenAndServe(handler.Port, nil) err = http.ListenAndServe(handler.Port, nil)
if err != nil { if err != nil {

View File

@ -60,6 +60,12 @@ func (router *Router) UpdateTLSVersion(requireLatest bool) {
router.Restart() router.Restart()
} }
// Update port 80 listener state
func (router *Router) UpdatePort80ListenerState(useRedirect bool) {
router.Option.ListenOnPort80 = useRedirect
router.Restart()
}
// Update https redirect, which will require updates // Update https redirect, which will require updates
func (router *Router) UpdateHttpToHttpsRedirectSetting(useRedirect bool) { func (router *Router) UpdateHttpToHttpsRedirectSetting(useRedirect bool) {
router.Option.ForceHttpsRedirect = useRedirect router.Option.ForceHttpsRedirect = useRedirect
@ -95,6 +101,7 @@ func (router *Router) StartProxyService() error {
} }
if router.Option.UseTls { if router.Option.UseTls {
/*
//Serve with TLS mode //Serve with TLS mode
ln, err := tls.Listen("tcp", ":"+strconv.Itoa(router.Option.Port), config) ln, err := tls.Listen("tcp", ":"+strconv.Itoa(router.Option.Port), config)
if err != nil { if err != nil {
@ -103,20 +110,65 @@ func (router *Router) StartProxyService() error {
return err return err
} }
router.tlsListener = ln router.tlsListener = ln
router.server = &http.Server{Addr: ":" + strconv.Itoa(router.Option.Port), Handler: router.mux} */
router.server = &http.Server{
Addr: ":" + strconv.Itoa(router.Option.Port),
Handler: router.mux,
TLSConfig: config,
}
router.Running = true router.Running = true
if router.Option.Port != 80 && router.Option.ForceHttpsRedirect { if router.Option.Port != 80 && router.Option.ListenOnPort80 {
//Add a 80 to 443 redirector //Add a 80 to 443 redirector
httpServer := &http.Server{ httpServer := &http.Server{
Addr: ":80", Addr: ":80",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
//Check if the domain requesting allow non TLS mode
domainOnly := r.Host
if strings.Contains(r.Host, ":") {
hostPath := strings.Split(r.Host, ":")
domainOnly = hostPath[0]
}
sep := router.getSubdomainProxyEndpointFromHostname(domainOnly)
if sep != nil && sep.BypassGlobalTLS {
//Allow routing via non-TLS handler
originalHostHeader := r.Host
if r.URL != nil {
r.Host = r.URL.Host
} else {
//Fallback when the upstream proxy screw something up in the header
r.URL, _ = url.Parse(originalHostHeader)
}
sep.Proxy.ServeHTTP(w, r, &dpcore.ResponseRewriteRuleSet{
ProxyDomain: sep.Domain,
OriginalHost: originalHostHeader,
UseTLS: sep.RequireTLS,
PathPrefix: "",
})
return
}
if router.Option.ForceHttpsRedirect {
//Redirect to https is enabled
protocol := "https://" protocol := "https://"
if router.Option.Port == 443 { if router.Option.Port == 443 {
http.Redirect(w, r, protocol+r.Host+r.RequestURI, http.StatusTemporaryRedirect) http.Redirect(w, r, protocol+r.Host+r.RequestURI, http.StatusTemporaryRedirect)
} else { } else {
http.Redirect(w, r, protocol+r.Host+":"+strconv.Itoa(router.Option.Port)+r.RequestURI, http.StatusTemporaryRedirect) http.Redirect(w, r, protocol+r.Host+":"+strconv.Itoa(router.Option.Port)+r.RequestURI, http.StatusTemporaryRedirect)
} }
} else {
//Do not do redirection
if sep != nil {
//Sub-domain exists but not allow non-TLS access
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("400 - Bad Request"))
} else {
//No defined sub-domain
http.NotFound(w, r)
}
}
}), }),
ReadTimeout: 3 * time.Second, ReadTimeout: 3 * time.Second,
@ -143,7 +195,7 @@ func (router *Router) StartProxyService() error {
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
//Unable to startup port 80 listener. Handle shutdown process gracefully //Unable to startup port 80 listener. Handle shutdown process gracefully
stopChan <- true stopChan <- true
log.Fatalf("Could not start server: %v\n", err) log.Fatalf("Could not start redirection server: %v\n", err)
} }
}() }()
router.tlsRedirectStop = stopChan router.tlsRedirectStop = stopChan
@ -152,8 +204,8 @@ func (router *Router) StartProxyService() error {
//Start the TLS server //Start the TLS server
log.Println("Reverse proxy service started in the background (TLS mode)") log.Println("Reverse proxy service started in the background (TLS mode)")
go func() { go func() {
if err := router.server.Serve(ln); err != nil && err != http.ErrServerClosed { if err := router.server.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
log.Fatalf("Could not start server: %v\n", err) log.Fatalf("Could not start proxy server: %v\n", err)
} }
}() }()
} else { } else {

View File

@ -38,6 +38,7 @@ func (router *Router) AddSubdomainRoutingService(options *SubdOptions) error {
Domain: domain, Domain: domain,
RequireTLS: options.RequireTLS, RequireTLS: options.RequireTLS,
Proxy: proxy, Proxy: proxy,
BypassGlobalTLS: options.BypassGlobalTLS,
SkipCertValidations: options.SkipCertValidations, SkipCertValidations: options.SkipCertValidations,
RequireBasicAuth: options.RequireBasicAuth, RequireBasicAuth: options.RequireBasicAuth,
BasicAuthCredentials: options.BasicAuthCredentials, BasicAuthCredentials: options.BasicAuthCredentials,

View File

@ -27,6 +27,7 @@ type RouterOption struct {
Port int //Incoming port Port int //Incoming port
UseTls bool //Use TLS to serve incoming requsts UseTls bool //Use TLS to serve incoming requsts
ForceTLSLatest bool //Force TLS1.2 or above ForceTLSLatest bool //Force TLS1.2 or above
ListenOnPort80 bool //Enable port 80 http listener
ForceHttpsRedirect bool //Force redirection of http to https endpoint ForceHttpsRedirect bool //Force redirection of http to https endpoint
TlsManager *tlscert.Manager TlsManager *tlscert.Manager
RedirectRuleTable *redirection.RuleTable RedirectRuleTable *redirection.RuleTable

View File

@ -0,0 +1,103 @@
package logger
import (
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"time"
)
/*
Zoraxy Logger
This script is designed to make a managed log for the Zoraxy
and replace the ton of log.Println in the system core
*/
type Logger struct {
LogToFile bool //Set enable write to file
Prefix string //Prefix for log files
LogFolder string //Folder to store the log file
CurrentLogFile string //Current writing filename
file *os.File
}
func NewLogger(logFilePrefix string, logFolder string, logToFile bool) (*Logger, error) {
err := os.MkdirAll(logFolder, 0775)
if err != nil {
return nil, err
}
thisLogger := Logger{
LogToFile: logToFile,
Prefix: logFilePrefix,
LogFolder: logFolder,
}
logFilePath := thisLogger.getLogFilepath()
f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
return nil, err
}
thisLogger.CurrentLogFile = logFilePath
thisLogger.file = f
return &thisLogger, nil
}
func (l *Logger) getLogFilepath() string {
year, month, _ := time.Now().Date()
return filepath.Join(l.LogFolder, l.Prefix+"_"+strconv.Itoa(year)+"-"+strconv.Itoa(int(month))+".log")
}
// PrintAndLog will log the message to file and print the log to STDOUT
func (l *Logger) PrintAndLog(title string, message string, originalError error) {
go func() {
l.Log(title, message, originalError)
}()
log.Println("[" + title + "] " + message)
}
// Println is a fast snap-in replacement for log.Println
func (l *Logger) Println(v ...interface{}) {
//Convert the array of interfaces into string
message := fmt.Sprint(v...)
go func() {
l.Log("info", string(message), nil)
}()
log.Println("[INFO] " + string(message))
}
func (l *Logger) Log(title string, errorMessage string, originalError error) {
l.ValidateAndUpdateLogFilepath()
if l.LogToFile {
if originalError == nil {
l.file.WriteString(time.Now().Format("2006-01-02 15:04:05.000000") + "|" + fmt.Sprintf("%-16s", title) + " [INFO]" + errorMessage + "\n")
} else {
l.file.WriteString(time.Now().Format("2006-01-02 15:04:05.000000") + "|" + fmt.Sprintf("%-16s", title) + " [ERROR]" + errorMessage + " " + originalError.Error() + "\n")
}
}
}
// Validate if the logging target is still valid (detect any months change)
func (l *Logger) ValidateAndUpdateLogFilepath() {
expectedCurrentLogFilepath := l.getLogFilepath()
if l.CurrentLogFile != expectedCurrentLogFilepath {
//Change of month. Update to a new log file
l.file.Close()
f, err := os.OpenFile(expectedCurrentLogFilepath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
log.Println("[Logger] Unable to create new log. Logging to file disabled.")
l.LogToFile = false
return
}
l.CurrentLogFile = expectedCurrentLogFilepath
l.file = f
}
}
func (l *Logger) Close() {
l.file.Close()
}

View File

@ -0,0 +1,122 @@
package logviewer
import (
"encoding/json"
"errors"
"io/fs"
"net/http"
"os"
"path/filepath"
"strings"
"imuslab.com/zoraxy/mod/utils"
)
type ViewerOption struct {
RootFolder string //The root folder to scan for log
Extension string //The extension the root files use, include the . in your ext (e.g. .log)
}
type Viewer struct {
option *ViewerOption
}
type LogFile struct {
Title string
Filename string
Fullpath string
Filesize int64
}
func NewLogViewer(option *ViewerOption) *Viewer {
return &Viewer{option: option}
}
/*
Log Request Handlers
*/
//List all the log files in the log folder. Return in map[string]LogFile format
func (v *Viewer) HandleListLog(w http.ResponseWriter, r *http.Request) {
logFiles := v.ListLogFiles(false)
js, _ := json.Marshal(logFiles)
utils.SendJSONResponse(w, string(js))
}
// Read log of a given catergory and filename
// Require GET varaible: file and catergory
func (v *Viewer) HandleReadLog(w http.ResponseWriter, r *http.Request) {
filename, err := utils.GetPara(r, "file")
if err != nil {
utils.SendErrorResponse(w, "invalid filename given")
return
}
catergory, err := utils.GetPara(r, "catergory")
if err != nil {
utils.SendErrorResponse(w, "invalid catergory given")
return
}
content, err := v.LoadLogFile(strings.TrimSpace(filepath.Base(catergory)), strings.TrimSpace(filepath.Base(filename)))
if err != nil {
utils.SendErrorResponse(w, err.Error())
return
}
utils.SendTextResponse(w, content)
}
/*
Log Access Functions
*/
func (v *Viewer) ListLogFiles(showFullpath bool) map[string][]*LogFile {
result := map[string][]*LogFile{}
filepath.WalkDir(v.option.RootFolder, func(path string, di fs.DirEntry, err error) error {
if filepath.Ext(path) == v.option.Extension {
catergory := filepath.Base(filepath.Dir(path))
logList, ok := result[catergory]
if !ok {
//this catergory hasn't been scanned before.
logList = []*LogFile{}
}
fullpath := filepath.ToSlash(path)
if !showFullpath {
fullpath = ""
}
st, err := os.Stat(path)
if err != nil {
return nil
}
logList = append(logList, &LogFile{
Title: strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)),
Filename: filepath.Base(path),
Fullpath: fullpath,
Filesize: st.Size(),
})
result[catergory] = logList
}
return nil
})
return result
}
func (v *Viewer) LoadLogFile(catergory string, filename string) (string, error) {
logFilepath := filepath.Join(v.option.RootFolder, catergory, filename)
if utils.FileExists(logFilepath) {
//Load it
content, err := os.ReadFile(logFilepath)
if err != nil {
return "", err
}
return string(content), nil
} else {
return "", errors.New("log file not found")
}
}

View File

@ -2,7 +2,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"log"
"net/http" "net/http"
"path/filepath" "path/filepath"
"sort" "sort"
@ -25,33 +24,43 @@ func ReverseProxtInit() {
inboundPort := 80 inboundPort := 80
if sysdb.KeyExists("settings", "inbound") { if sysdb.KeyExists("settings", "inbound") {
sysdb.Read("settings", "inbound", &inboundPort) sysdb.Read("settings", "inbound", &inboundPort)
log.Println("Serving inbound port ", inboundPort) SystemWideLogger.Println("Serving inbound port ", inboundPort)
} else { } else {
log.Println("Inbound port not set. Using default (80)") SystemWideLogger.Println("Inbound port not set. Using default (80)")
} }
useTls := false useTls := false
sysdb.Read("settings", "usetls", &useTls) sysdb.Read("settings", "usetls", &useTls)
if useTls { if useTls {
log.Println("TLS mode enabled. Serving proxxy request with TLS") SystemWideLogger.Println("TLS mode enabled. Serving proxxy request with TLS")
} else { } else {
log.Println("TLS mode disabled. Serving proxy request with plain http") SystemWideLogger.Println("TLS mode disabled. Serving proxy request with plain http")
} }
forceLatestTLSVersion := false forceLatestTLSVersion := false
sysdb.Read("settings", "forceLatestTLS", &forceLatestTLSVersion) sysdb.Read("settings", "forceLatestTLS", &forceLatestTLSVersion)
if forceLatestTLSVersion { if forceLatestTLSVersion {
log.Println("Force latest TLS mode enabled. Minimum TLS LS version is set to v1.2") SystemWideLogger.Println("Force latest TLS mode enabled. Minimum TLS LS version is set to v1.2")
} else { } else {
log.Println("Force latest TLS mode disabled. Minimum TLS version is set to v1.0") SystemWideLogger.Println("Force latest TLS mode disabled. Minimum TLS version is set to v1.0")
}
listenOnPort80 := false
sysdb.Read("settings", "listenP80", &listenOnPort80)
if listenOnPort80 {
SystemWideLogger.Println("Port 80 listener enabled")
} else {
SystemWideLogger.Println("Port 80 listener disabled")
} }
forceHttpsRedirect := false forceHttpsRedirect := false
sysdb.Read("settings", "redirect", &forceHttpsRedirect) sysdb.Read("settings", "redirect", &forceHttpsRedirect)
if forceHttpsRedirect { if forceHttpsRedirect {
log.Println("Force HTTPS mode enabled") SystemWideLogger.Println("Force HTTPS mode enabled")
//Port 80 listener must be enabled to perform http -> https redirect
listenOnPort80 = true
} else { } else {
log.Println("Force HTTPS mode disabled") SystemWideLogger.Println("Force HTTPS mode disabled")
} }
dprouter, err := dynamicproxy.NewDynamicProxy(dynamicproxy.RouterOption{ dprouter, err := dynamicproxy.NewDynamicProxy(dynamicproxy.RouterOption{
@ -59,6 +68,7 @@ func ReverseProxtInit() {
Port: inboundPort, Port: inboundPort,
UseTls: useTls, UseTls: useTls,
ForceTLSLatest: forceLatestTLSVersion, ForceTLSLatest: forceLatestTLSVersion,
ListenOnPort80: listenOnPort80,
ForceHttpsRedirect: forceHttpsRedirect, ForceHttpsRedirect: forceHttpsRedirect,
TlsManager: tlsCertManager, TlsManager: tlsCertManager,
RedirectRuleTable: redirectTable, RedirectRuleTable: redirectTable,
@ -67,7 +77,7 @@ func ReverseProxtInit() {
WebDirectory: *staticWebServerRoot, WebDirectory: *staticWebServerRoot,
}) })
if err != nil { if err != nil {
log.Println(err.Error()) SystemWideLogger.PrintAndLog("Proxy", "Unable to create dynamic proxy router", err)
return return
} }
@ -78,7 +88,7 @@ func ReverseProxtInit() {
for _, conf := range confs { for _, conf := range confs {
record, err := LoadReverseProxyConfig(conf) record, err := LoadReverseProxyConfig(conf)
if err != nil { if err != nil {
log.Println("Failed to load "+filepath.Base(conf), err.Error()) SystemWideLogger.PrintAndLog("Proxy", "Failed to load config file: "+filepath.Base(conf), err)
return return
} }
@ -92,6 +102,7 @@ func ReverseProxtInit() {
MatchingDomain: record.Rootname, MatchingDomain: record.Rootname,
Domain: record.ProxyTarget, Domain: record.ProxyTarget,
RequireTLS: record.UseTLS, RequireTLS: record.UseTLS,
BypassGlobalTLS: record.BypassGlobalTLS,
SkipCertValidations: record.SkipTlsValidation, SkipCertValidations: record.SkipTlsValidation,
RequireBasicAuth: record.RequireBasicAuth, RequireBasicAuth: record.RequireBasicAuth,
BasicAuthCredentials: record.BasicAuthCredentials, BasicAuthCredentials: record.BasicAuthCredentials,
@ -102,13 +113,14 @@ func ReverseProxtInit() {
RootName: record.Rootname, RootName: record.Rootname,
Domain: record.ProxyTarget, Domain: record.ProxyTarget,
RequireTLS: record.UseTLS, RequireTLS: record.UseTLS,
BypassGlobalTLS: record.BypassGlobalTLS,
SkipCertValidations: record.SkipTlsValidation, SkipCertValidations: record.SkipTlsValidation,
RequireBasicAuth: record.RequireBasicAuth, RequireBasicAuth: record.RequireBasicAuth,
BasicAuthCredentials: record.BasicAuthCredentials, BasicAuthCredentials: record.BasicAuthCredentials,
BasicAuthExceptionRules: record.BasicAuthExceptionRules, BasicAuthExceptionRules: record.BasicAuthExceptionRules,
}) })
} else { } else {
log.Println("Unsupported endpoint type: " + record.ProxyType + ". Skipping " + filepath.Base(conf)) SystemWideLogger.PrintAndLog("Proxy", "Unsupported endpoint type: "+record.ProxyType+". Skipping "+filepath.Base(conf), nil)
} }
} }
@ -117,7 +129,7 @@ func ReverseProxtInit() {
//reverse proxy server in front of this service //reverse proxy server in front of this service
time.Sleep(300 * time.Millisecond) time.Sleep(300 * time.Millisecond)
dynamicProxyRouter.StartProxyService() dynamicProxyRouter.StartProxyService()
log.Println("Dynamic Reverse Proxy service started") SystemWideLogger.Println("Dynamic Reverse Proxy service started")
//Add all proxy services to uptime monitor //Add all proxy services to uptime monitor
//Create a uptime monitor service //Create a uptime monitor service
@ -128,7 +140,7 @@ func ReverseProxtInit() {
Interval: 300, //5 minutes Interval: 300, //5 minutes
MaxRecordsStore: 288, //1 day MaxRecordsStore: 288, //1 day
}) })
log.Println("Uptime Monitor background service started") SystemWideLogger.Println("Uptime Monitor background service started")
}() }()
} }
@ -180,6 +192,13 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
useTLS := (tls == "true") useTLS := (tls == "true")
bypassGlobalTLS, _ := utils.PostPara(r, "bypassGlobalTLS")
if bypassGlobalTLS == "" {
bypassGlobalTLS = "false"
}
useBypassGlobalTLS := bypassGlobalTLS == "true"
stv, _ := utils.PostPara(r, "tlsval") stv, _ := utils.PostPara(r, "tlsval")
if stv == "" { if stv == "" {
stv = "false" stv = "false"
@ -240,6 +259,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
RootName: vdir, RootName: vdir,
Domain: endpoint, Domain: endpoint,
RequireTLS: useTLS, RequireTLS: useTLS,
BypassGlobalTLS: useBypassGlobalTLS,
SkipCertValidations: skipTlsValidation, SkipCertValidations: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: basicAuthCredentials, BasicAuthCredentials: basicAuthCredentials,
@ -257,6 +277,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
MatchingDomain: subdomain, MatchingDomain: subdomain,
Domain: endpoint, Domain: endpoint,
RequireTLS: useTLS, RequireTLS: useTLS,
BypassGlobalTLS: useBypassGlobalTLS,
SkipCertValidations: skipTlsValidation, SkipCertValidations: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: basicAuthCredentials, BasicAuthCredentials: basicAuthCredentials,
@ -281,6 +302,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
Rootname: rootname, Rootname: rootname,
ProxyTarget: endpoint, ProxyTarget: endpoint,
UseTLS: useTLS, UseTLS: useTLS,
BypassGlobalTLS: useBypassGlobalTLS,
SkipTlsValidation: skipTlsValidation, SkipTlsValidation: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: basicAuthCredentials, BasicAuthCredentials: basicAuthCredentials,
@ -332,9 +354,15 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
if stv == "" { if stv == "" {
stv = "false" stv = "false"
} }
skipTlsValidation := (stv == "true") skipTlsValidation := (stv == "true")
//Load bypass TLS option
bpgtls, _ := utils.PostPara(r, "bpgtls")
if bpgtls == "" {
bpgtls = "false"
}
bypassGlobalTLS := (bpgtls == "true")
rba, _ := utils.PostPara(r, "bauth") rba, _ := utils.PostPara(r, "bauth")
if rba == "" { if rba == "" {
rba = "false" rba = "false"
@ -354,6 +382,7 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
RootName: targetProxyEntry.RootOrMatchingDomain, RootName: targetProxyEntry.RootOrMatchingDomain,
Domain: endpoint, Domain: endpoint,
RequireTLS: useTLS, RequireTLS: useTLS,
BypassGlobalTLS: false,
SkipCertValidations: skipTlsValidation, SkipCertValidations: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials, BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials,
@ -366,6 +395,7 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
MatchingDomain: targetProxyEntry.RootOrMatchingDomain, MatchingDomain: targetProxyEntry.RootOrMatchingDomain,
Domain: endpoint, Domain: endpoint,
RequireTLS: useTLS, RequireTLS: useTLS,
BypassGlobalTLS: bypassGlobalTLS,
SkipCertValidations: skipTlsValidation, SkipCertValidations: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials, BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials,
@ -385,6 +415,10 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials, BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials,
} }
SaveReverseProxyConfigToFile(&thisProxyConfigRecord) SaveReverseProxyConfigToFile(&thisProxyConfigRecord)
//Update uptime monitor
UpdateUptimeMonitorTargets()
utils.SendOK(w) utils.SendOK(w)
} }
@ -417,6 +451,9 @@ func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) {
uptimeMonitor.CleanRecords() uptimeMonitor.CleanRecords()
} }
//Update uptime monitor
UpdateUptimeMonitorTargets()
utils.SendOK(w) utils.SendOK(w)
} }
@ -731,6 +768,35 @@ func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
} }
} }
// Handle port 80 incoming traffics
func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) {
enabled, err := utils.GetPara(r, "enable")
if err != nil {
//Load the current status
currentEnabled := false
err = sysdb.Read("settings", "listenP80", &currentEnabled)
if err != nil {
utils.SendErrorResponse(w, err.Error())
return
}
js, _ := json.Marshal(currentEnabled)
utils.SendJSONResponse(w, string(js))
} else {
if enabled == "true" {
sysdb.Write("settings", "listenP80", true)
SystemWideLogger.Println("Enabling port 80 listener")
dynamicProxyRouter.UpdatePort80ListenerState(true)
} else if enabled == "false" {
sysdb.Write("settings", "listenP80", false)
SystemWideLogger.Println("Disabling port 80 listener")
dynamicProxyRouter.UpdatePort80ListenerState(true)
} else {
utils.SendErrorResponse(w, "invalid mode given: "+enabled)
}
utils.SendOK(w)
}
}
// Handle https redirect // Handle https redirect
func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) { func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) {
useRedirect, err := utils.GetPara(r, "set") useRedirect, err := utils.GetPara(r, "set")
@ -751,11 +817,11 @@ func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) {
} }
if useRedirect == "true" { if useRedirect == "true" {
sysdb.Write("settings", "redirect", true) sysdb.Write("settings", "redirect", true)
log.Println("Updating force HTTPS redirection to true") SystemWideLogger.Println("Updating force HTTPS redirection to true")
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
} else if useRedirect == "false" { } else if useRedirect == "false" {
sysdb.Write("settings", "redirect", false) sysdb.Write("settings", "redirect", false)
log.Println("Updating force HTTPS redirection to false") SystemWideLogger.Println("Updating force HTTPS redirection to false")
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false)
} }

View File

@ -14,6 +14,7 @@ import (
"imuslab.com/zoraxy/mod/dynamicproxy/redirection" "imuslab.com/zoraxy/mod/dynamicproxy/redirection"
"imuslab.com/zoraxy/mod/ganserv" "imuslab.com/zoraxy/mod/ganserv"
"imuslab.com/zoraxy/mod/geodb" "imuslab.com/zoraxy/mod/geodb"
"imuslab.com/zoraxy/mod/info/logger"
"imuslab.com/zoraxy/mod/mdns" "imuslab.com/zoraxy/mod/mdns"
"imuslab.com/zoraxy/mod/netstat" "imuslab.com/zoraxy/mod/netstat"
"imuslab.com/zoraxy/mod/pathrule" "imuslab.com/zoraxy/mod/pathrule"
@ -93,10 +94,17 @@ func startupSequence() {
panic(err) panic(err)
} }
//Create a system wide logger
l, err := logger.NewLogger("zr", "./log", *logOutputToFile)
if err == nil {
SystemWideLogger = l
} else {
panic(err)
}
//Create a netstat buffer //Create a netstat buffer
netstatBuffers, err = netstat.NewNetStatBuffer(300) netstatBuffers, err = netstat.NewNetStatBuffer(300)
if err != nil { if err != nil {
log.Println("Failed to load network statistic info") SystemWideLogger.PrintAndLog("Network", "Failed to load network statistic info", err)
panic(err) panic(err)
} }
@ -134,13 +142,13 @@ func startupSequence() {
BuildVersion: version, BuildVersion: version,
}, "") }, "")
if err != nil { if err != nil {
log.Println("Unable to startup mDNS service. Disabling mDNS services") SystemWideLogger.Println("Unable to startup mDNS service. Disabling mDNS services")
} else { } else {
//Start initial scanning //Start initial scanning
go func() { go func() {
hosts := mdnsScanner.Scan(30, "") hosts := mdnsScanner.Scan(30, "")
previousmdnsScanResults = hosts previousmdnsScanResults = hosts
log.Println("mDNS Startup scan completed") SystemWideLogger.Println("mDNS Startup scan completed")
}() }()
//Create a ticker to update mDNS results every 5 minutes //Create a ticker to update mDNS results every 5 minutes
@ -154,7 +162,7 @@ func startupSequence() {
case <-ticker.C: case <-ticker.C:
hosts := mdnsScanner.Scan(30, "") hosts := mdnsScanner.Scan(30, "")
previousmdnsScanResults = hosts previousmdnsScanResults = hosts
log.Println("mDNS scan result updated") SystemWideLogger.Println("mDNS scan result updated")
} }
} }
}() }()
@ -171,7 +179,7 @@ func startupSequence() {
if usingZtAuthToken == "" { if usingZtAuthToken == "" {
usingZtAuthToken, err = ganserv.TryLoadorAskUserForAuthkey() usingZtAuthToken, err = ganserv.TryLoadorAskUserForAuthkey()
if err != nil { if err != nil {
log.Println("Failed to load ZeroTier controller API authtoken") SystemWideLogger.Println("Failed to load ZeroTier controller API authtoken")
} }
} }
ganManager = ganserv.NewNetworkManager(&ganserv.NetworkManagerOptions{ ganManager = ganserv.NewNetworkManager(&ganserv.NetworkManagerOptions{
@ -220,7 +228,7 @@ func startupSequence() {
staticWebServer = webserv.NewWebServer(&webserv.WebServerOptions{ staticWebServer = webserv.NewWebServer(&webserv.WebServerOptions{
Sysdb: sysdb, Sysdb: sysdb,
Port: "8081", //Default Port Port: "5487", //Default Port
WebRoot: *staticWebServerRoot, WebRoot: *staticWebServerRoot,
EnableDirectoryListing: true, EnableDirectoryListing: true,
EnableWebDirManager: *allowWebFileManager, EnableWebDirManager: *allowWebFileManager,

View File

@ -75,13 +75,13 @@
$("#rootReqTLS").parent().addClass("disabled"); $("#rootReqTLS").parent().addClass("disabled");
//Check if web server is enabled. If not, ask if the user want to enable it //Check if web server is enabled. If not, ask if the user want to enable it
if (!$("#webserv_enable").parent().checkbox("is checked")){ /*if (!$("#webserv_enable").parent().checkbox("is checked")){
confirmBox("Enable static web server now?", function(choice){ confirmBox("Enable static web server now?", function(choice){
if (choice == true){ if (choice == true){
$("#webserv_enable").parent().checkbox("set checked"); $("#webserv_enable").parent().checkbox("set checked");
} }
}); });
} }*/
}else{ }else{
$("#rootReqTLS").parent().removeClass("disabled"); $("#rootReqTLS").parent().removeClass("disabled");
$("#proxyRoot").parent().removeClass("disabled"); $("#proxyRoot").parent().removeClass("disabled");
@ -89,7 +89,7 @@
} }
} }
function initRootInfo(){ function initRootInfo(callback=undefined){
$.get("/api/proxy/list?type=root", function(data){ $.get("/api/proxy/list?type=root", function(data){
if (data == null){ if (data == null){
@ -97,10 +97,39 @@
$("#proxyRoot").val(data.Domain); $("#proxyRoot").val(data.Domain);
checkRootRequireTLS(data.Domain); checkRootRequireTLS(data.Domain);
} }
if (callback != undefined){
callback();
}
});
}
initRootInfo(function(){
updateWebServerLinkSettings();
});
//Update the current web server port settings
function updateWebServerLinkSettings(){
isUsingStaticWebServerAsRoot(function(isUsingWebServ){
if (isUsingWebServ){
$(".webservRootDisabled").addClass("disabled");
$("#useStaticWebServer").parent().checkbox("set checked");
}else{
$(".webservRootDisabled").removeClass("disabled");
$("#useStaticWebServer").parent().checkbox("set unchecked");
}
})
}
function isUsingStaticWebServerAsRoot(callback){
let currentProxyRoot = $("#proxyRoot").val().trim();
$.get("/api/webserv/status", function(webservStatus){
if (currentProxyRoot == "127.0.0.1:" + webservStatus.ListeningPort || currentProxyRoot == "localhost:" + webservStatus.ListeningPort){
return callback(true);
}
return callback(false);
}); });
} }
initRootInfo();
function updateRootSettingStates(){ function updateRootSettingStates(){
$.get("/api/cert/tls", function(data){ $.get("/api/cert/tls", function(data){
@ -111,6 +140,7 @@
} }
}); });
} }
//Bind event to tab switch //Bind event to tab switch
tabSwitchEventBind["setroot"] = function(){ tabSwitchEventBind["setroot"] = function(){
//On switch over to this page, update root info //On switch over to this page, update root info
@ -137,11 +167,12 @@
let useRedirect = $("#unsetRedirect")[0].checked; let useRedirect = $("#unsetRedirect")[0].checked;
updateRedirectionDomainSettingInputBox(useRedirect); updateRedirectionDomainSettingInputBox(useRedirect);
}); });
}) });
} }
checkCustomRedirectForUnsetSubd(); checkCustomRedirectForUnsetSubd();
//Check if the given domain will redirect to https
function checkRootRequireTLS(targetDomain){ function checkRootRequireTLS(targetDomain){
//Trim off the http or https from the origin //Trim off the http or https from the origin
if (targetDomain.startsWith("http://")){ if (targetDomain.startsWith("http://")){
@ -168,7 +199,7 @@
}) })
} }
//Set the new proxy root option
function setProxyRoot(){ function setProxyRoot(){
var newpr = $("#proxyRoot").val(); var newpr = $("#proxyRoot").val();
if (newpr.trim() == ""){ if (newpr.trim() == ""){
@ -189,8 +220,24 @@
msgbox(data.error, false, 5000); msgbox(data.error, false, 5000);
}else{ }else{
//OK //OK
initRootInfo(); initRootInfo(function(){
msgbox("Proxy Root Updated") //Check if WebServ is enabled
isUsingStaticWebServerAsRoot(function(isUsingWebServ){
if (isUsingWebServ){
//Force enable static web server
//See webserv.html for details
setWebServerRunningState(true);
}
setTimeout(function(){
//Update the checkbox
updateWebServerLinkSettings();
msgbox("Proxy Root Updated");
}, 1000);
})
});
} }
} }
}); });

View File

@ -8,7 +8,7 @@
<div class="field"> <div class="field">
<label>Proxy Type</label> <label>Proxy Type</label>
<div class="ui selection dropdown"> <div class="ui selection dropdown">
<input type="hidden" id="ptype" value="subd"> <input type="hidden" id="ptype" value="subd" onchange="handleProxyTypeOptionChange(this.value)">
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
<div class="default text">Proxy Type</div> <div class="default text">Proxy Type</div>
<div class="menu"> <div class="menu">
@ -22,7 +22,7 @@
<input type="text" id="rootname" placeholder="s1.mydomain.com"> <input type="text" id="rootname" placeholder="s1.mydomain.com">
</div> </div>
<div class="field"> <div class="field">
<label>IP Address or Domain Name with port</label> <label>Target IP Address or Domain Name with port</label>
<input type="text" id="proxyDomain" onchange="autoCheckTls(this.value);"> <input type="text" id="proxyDomain" onchange="autoCheckTls(this.value);">
<small>E.g. 192.168.0.101:8000 or example.com</small> <small>E.g. 192.168.0.101:8000 or example.com</small>
</div> </div>
@ -44,7 +44,13 @@
<div class="field"> <div class="field">
<div class="ui checkbox"> <div class="ui checkbox">
<input type="checkbox" id="skipTLSValidation"> <input type="checkbox" id="skipTLSValidation">
<label>Ignore TLS/SSL Verification Error<br><small>E.g. self-signed, expired certificate (Not Recommended)</small></label> <label>Ignore TLS/SSL Verification Error<br><small>For targets that is using self-signed, expired certificate (Not Recommended)</small></label>
</div>
</div>
<div class="field">
<div class="ui checkbox">
<input type="checkbox" id="bypassGlobalTLS">
<label>Allow plain HTTP access<br><small>Allow this subdomain to be connected without TLS (Require HTTP server enabled on port 80)</small></label>
</div> </div>
</div> </div>
<div class="field"> <div class="field">
@ -123,6 +129,7 @@
var proxyDomain = $("#proxyDomain").val(); var proxyDomain = $("#proxyDomain").val();
var useTLS = $("#reqTls")[0].checked; var useTLS = $("#reqTls")[0].checked;
var skipTLSValidation = $("#skipTLSValidation")[0].checked; var skipTLSValidation = $("#skipTLSValidation")[0].checked;
var bypassGlobalTLS = $("#bypassGlobalTLS")[0].checked;
var requireBasicAuth = $("#requireBasicAuth")[0].checked; var requireBasicAuth = $("#requireBasicAuth")[0].checked;
if (type === "vdir") { if (type === "vdir") {
@ -162,6 +169,7 @@
tls: useTLS, tls: useTLS,
ep: proxyDomain, ep: proxyDomain,
tlsval: skipTLSValidation, tlsval: skipTLSValidation,
bypassGlobalTLS: bypassGlobalTLS,
bauth: requireBasicAuth, bauth: requireBasicAuth,
cred: JSON.stringify(credentials), cred: JSON.stringify(credentials),
}, },
@ -206,6 +214,14 @@
} }
function handleProxyTypeOptionChange(newType){
if (newType == "subd"){
$("#bypassGlobalTLS").parent().removeClass("disabled");
}else if (newType == "vdir"){
$("#bypassGlobalTLS").parent().addClass("disabled");
}
}
//Generic functions for delete rp endpoints //Generic functions for delete rp endpoints
function deleteEndpoint(ptype, epoint){ function deleteEndpoint(ptype, epoint){
if (confirm("Confirm remove proxy for :" + epoint + " (type: " + ptype + ")?")){ if (confirm("Confirm remove proxy for :" + epoint + " (type: " + ptype + ")?")){
@ -331,7 +347,7 @@
var columns = row.find('td[data-label]'); var columns = row.find('td[data-label]');
var payload = $(row).attr("payload"); var payload = $(row).attr("payload");
payload = JSON.parse(decodeURIComponent(payload)); payload = JSON.parse(decodeURIComponent(payload));
console.log(payload);
//console.log(payload); //console.log(payload);
columns.each(function(index) { columns.each(function(index) {
var column = $(this); var column = $(this);
@ -347,34 +363,37 @@
var datatype = $(this).attr("datatype"); var datatype = $(this).attr("datatype");
if (datatype == "domain"){ if (datatype == "domain"){
let domain = payload.Domain; let domain = payload.Domain;
//Target require TLS for proxying
let tls = payload.RequireTLS; let tls = payload.RequireTLS;
if (tls){ if (tls){
tls = "checked"; tls = "checked";
}else{ }else{
tls = ""; tls = "";
} }
//Require TLS validation
let skipTLSValidation = payload.SkipCertValidations;
let checkstate = "";
if (skipTLSValidation){
checkstate = "checked";
}
input = ` input = `
<div class="ui mini fluid input"> <div class="ui mini fluid input">
<input type="text" class="Domain" value="${domain}"> <input type="text" class="Domain" value="${domain}">
</div> </div>
<div class="ui checkbox" style="margin-top: 0.4em;"> <div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="RequireTLS" ${tls}> <input type="checkbox" class="RequireTLS" ${tls}>
<label>Require TLS</label> <label>Require TLS<br>
<small>Proxy target require HTTPS connection</small></label>
</div><br>
<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="SkipCertValidations" ${checkstate}>
<label>Skip Verification<br>
<small>Check this if proxy target is using self signed certificates</small></label>
</div> </div>
`; `;
column.empty().append(input); column.empty().append(input);
}else if (datatype == "skipver"){
let skipTLSValidation = payload.SkipCertValidations;
let checkstate = "";
if (skipTLSValidation){
checkstate = "checked";
}
column.empty().append(`<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="SkipCertValidations" ${checkstate}>
<label>Skip Verification</label>
<small>Check this if you are using self signed certificates</small>
</div>`);
}else if (datatype == "basicauth"){ }else if (datatype == "basicauth"){
let requireBasicAuth = payload.RequireBasicAuth; let requireBasicAuth = payload.RequireBasicAuth;
let checkstate = ""; let checkstate = "";
@ -392,6 +411,16 @@
<button title="Cancel" onclick="exitProxyInlineEdit('${endpointType}');" class="ui basic small circular icon button"><i class="ui remove icon"></i></button> <button title="Cancel" onclick="exitProxyInlineEdit('${endpointType}');" class="ui basic small circular icon button"><i class="ui remove icon"></i></button>
<button title="Save" onclick="saveProxyInlineEdit('${uuid}');" class="ui basic small circular icon button"><i class="ui green save icon"></i></button> <button title="Save" onclick="saveProxyInlineEdit('${uuid}');" class="ui basic small circular icon button"><i class="ui green save icon"></i></button>
`); `);
}else if (datatype == "inbound" && payload.ProxyType == 0){
let originalContent = $(column).html();
column.empty().append(`${originalContent}
<div class="ui divider"></div>
<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="BypassGlobalTLS" ${payload.BypassGlobalTLS?"checked":""}>
<label>Allow plain HTTP access<br>
<small>Allow inbound connections without TLS/SSL</small></label>
</div><br>
`);
}else{ }else{
//Unknown field. Leave it untouched //Unknown field. Leave it untouched
} }
@ -423,6 +452,7 @@
let requireTLS = $(row).find(".RequireTLS")[0].checked; let requireTLS = $(row).find(".RequireTLS")[0].checked;
let skipCertValidations = $(row).find(".SkipCertValidations")[0].checked; let skipCertValidations = $(row).find(".SkipCertValidations")[0].checked;
let requireBasicAuth = $(row).find(".RequireBasicAuth")[0].checked; let requireBasicAuth = $(row).find(".RequireBasicAuth")[0].checked;
let bypassGlobalTLS = $(row).find(".BypassGlobalTLS")[0].checked;
console.log(newDomain, requireTLS, skipCertValidations, requireBasicAuth) console.log(newDomain, requireTLS, skipCertValidations, requireBasicAuth)
@ -433,6 +463,7 @@
"type": epttype, "type": epttype,
"rootname": uuid, "rootname": uuid,
"ep":newDomain, "ep":newDomain,
"bpgtls": bypassGlobalTLS,
"tls" :requireTLS, "tls" :requireTLS,
"tlsval": skipCertValidations, "tlsval": skipCertValidations,
"bauth" :requireBasicAuth, "bauth" :requireBasicAuth,

View File

@ -72,10 +72,15 @@
<label>Use TLS to serve proxy request</label> <label>Use TLS to serve proxy request</label>
</div> </div>
<br> <br>
<div id="redirect" class="ui toggle notloopbackOnly tlsEnabledOnly checkbox" style="margin-top: 0.6em;"> <div id="listenP80" class="ui toggle notloopbackOnly tlsEnabledOnly checkbox" style="margin-top: 0.6em;" >
<input type="checkbox"> <input type="checkbox">
<label>Force redirect HTTP request to HTTPS<br> <label>Enable HTTP server on port 80<br>
<small>(Only apply when listening port is not 80)</small></label> <small>(Only apply when TLS enabled and not using port 80)</small></label>
</div>
<br>
<div id="redirect" class="ui toggle notloopbackOnly tlsEnabledOnly checkbox" style="margin-top: 0.6em; padding-left: 2em;">
<input type="checkbox">
<label>Force redirect HTTP request to HTTPS</label>
</div> </div>
<div class="ui basic segment" style="background-color: #f7f7f7; border-radius: 1em;"> <div class="ui basic segment" style="background-color: #f7f7f7; border-radius: 1em;">
<div class="ui accordion advanceSettings"> <div class="ui accordion advanceSettings">
@ -181,6 +186,7 @@
$("#serverstatus").removeClass("green"); $("#serverstatus").removeClass("green");
} }
$("#incomingPort").val(data.Option.Port); $("#incomingPort").val(data.Option.Port);
}); });
} }
@ -305,6 +311,27 @@
}); });
} }
function handleP80ListenerStateChange(enabled){
$.ajax({
url: "/api/proxy/listenPort80",
data: {"enable": enabled},
success: function(data){
if (data.error != undefined){
console.log(data.error);
return;
}
if (enabled){
$("#redirect").show();
msgbox("Port 80 listener enabled");
}else{
$("#redirect").hide();
msgbox("Port 80 listener disabled");
}
}
});
}
function handlePortChange(){ function handlePortChange(){
var newPortValue = $("#incomingPort").val(); var newPortValue = $("#incomingPort").val();
@ -323,6 +350,25 @@
}); });
} }
function initPort80ListenerSetting(){
$.get("/api/proxy/listenPort80", function(data){
if (data){
$("#listenP80").checkbox("set checked");
$("#redirect").show();
}else{
$("#listenP80").checkbox("set unchecked");
$("#redirect").hide();
}
$("#listenP80").find("input").on("change", function(){
let enabled = $(this)[0].checked;
handleP80ListenerStateChange(enabled);
})
});
}
initPort80ListenerSetting();
function initHTTPtoHTTPSRedirectSetting(){ function initHTTPtoHTTPSRedirectSetting(){
$.get("/api/proxy/useHttpsRedirect", function(data){ $.get("/api/proxy/useHttpsRedirect", function(data){
if (data == true){ if (data == true){
@ -356,8 +402,6 @@
}) })
}); });
}); });
} }
initHTTPtoHTTPSRedirectSetting(); initHTTPtoHTTPSRedirectSetting();

View File

@ -9,7 +9,6 @@
<tr> <tr>
<th>Matching Domain</th> <th>Matching Domain</th>
<th>Proxy To</th> <th>Proxy To</th>
<th>TLS/SSL Verification</th>
<th>Basic Auth</th> <th>Basic Auth</th>
<th class="no-sort" style="min-width: 7.2em;">Actions</th> <th class="no-sort" style="min-width: 7.2em;">Actions</th>
</tr> </tr>
@ -41,19 +40,14 @@
let subdData = encodeURIComponent(JSON.stringify(subd)); let subdData = encodeURIComponent(JSON.stringify(subd));
if (subd.RequireTLS){ if (subd.RequireTLS){
tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`; tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
if (subd.SkipCertValidations){
tlsIcon = `<i class="yellow lock icon" title="TLS/SSL mode without verification"></i>`
} }
let tlsVerificationField = "";
if (subd.RequireTLS){
tlsVerificationField = !subd.SkipCertValidations?`<i class="ui green check icon"></i>`:`<i class="ui yellow exclamation circle icon" title="TLS/SSL Verification will be skipped on this host"></i>`
}else{
tlsVerificationField = "N/A"
} }
$("#subdList").append(`<tr eptuuid="${subd.RootOrMatchingDomain}" payload="${subdData}" class="subdEntry"> $("#subdList").append(`<tr eptuuid="${subd.RootOrMatchingDomain}" payload="${subdData}" class="subdEntry">
<td data-label="" editable="false"><a href="//${subd.RootOrMatchingDomain}" target="_blank">${subd.RootOrMatchingDomain}</a></td> <td data-label="" editable="true" datatype="inbound"><a href="//${subd.RootOrMatchingDomain}" target="_blank">${subd.RootOrMatchingDomain}</a></td>
<td data-label="" editable="true" datatype="domain">${subd.Domain} ${tlsIcon}</td> <td data-label="" editable="true" datatype="domain">${subd.Domain} ${tlsIcon}</td>
<td data-label="" editable="true" datatype="skipver">${tlsVerificationField}</td>
<td data-label="" editable="true" datatype="basicauth">${subd.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td> <td data-label="" editable="true" datatype="basicauth">${subd.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td>
<td class="center aligned" editable="true" datatype="action" data-label=""> <td class="center aligned" editable="true" datatype="action" data-label="">
<button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("subd","${subd.RootOrMatchingDomain}")'><i class="edit icon"></i></button> <button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("subd","${subd.RootOrMatchingDomain}")'><i class="edit icon"></i></button>

View File

@ -86,7 +86,7 @@
let id = value[0].ID; let id = value[0].ID;
let name = value[0].Name; let name = value[0].Name;
let url = value[0].URL; let url = value[value.length - 1].URL;
let protocol = value[0].Protocol; let protocol = value[0].Protocol;
//Generate the status dot //Generate the status dot
@ -112,6 +112,9 @@
if (thisStatus.StatusCode >= 500 && thisStatus.StatusCode < 600){ if (thisStatus.StatusCode >= 500 && thisStatus.StatusCode < 600){
//Special type of error, cause by downstream reverse proxy //Special type of error, cause by downstream reverse proxy
dotType = "error"; dotType = "error";
}else if (thisStatus.StatusCode == 401){
//Unauthorized error
dotType = "error";
}else{ }else{
dotType = "offline"; dotType = "offline";
} }
@ -141,6 +144,28 @@
currentOnlineStatus = `<i class="exclamation circle icon"></i> Misconfigured`; currentOnlineStatus = `<i class="exclamation circle icon"></i> Misconfigured`;
onlineStatusCss = `color: #f38020;`; onlineStatusCss = `color: #f38020;`;
reminderEle = `<small style="${onlineStatusCss}">Downstream proxy server is online with misconfigured settings</small>`; reminderEle = `<small style="${onlineStatusCss}">Downstream proxy server is online with misconfigured settings</small>`;
}else if (value[value.length - 1].StatusCode >= 400 && value[value.length - 1].StatusCode <= 405){
switch(value[value.length - 1].StatusCode){
case 400:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Bad Request`;
break;
case 401:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Unauthorized`;
break;
case 403:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Forbidden`;
break;
case 404:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Not Found`;
break;
case 405:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Method Not Allowed`;
break;
}
onlineStatusCss = `color: #f38020;`;
reminderEle = `<small style="${onlineStatusCss}">Target online but not accessible</small>`;
}else{ }else{
currentOnlineStatus = `<i class="circle icon"></i> Offline`; currentOnlineStatus = `<i class="circle icon"></i> Offline`;
onlineStatusCss = `color: #df484a;`; onlineStatusCss = `color: #df484a;`;

View File

@ -9,7 +9,6 @@
<tr> <tr>
<th>Virtual Directory</th> <th>Virtual Directory</th>
<th>Proxy To</th> <th>Proxy To</th>
<th>TLS/SSL Verification</th>
<th>Basic Auth</th> <th>Basic Auth</th>
<th class="no-sort" style="min-width: 7.2em;">Actions</th> <th class="no-sort" style="min-width: 7.2em;">Actions</th>
</tr> </tr>
@ -43,6 +42,9 @@
let vdirData = encodeURIComponent(JSON.stringify(vdir)); let vdirData = encodeURIComponent(JSON.stringify(vdir));
if (vdir.RequireTLS){ if (vdir.RequireTLS){
tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`; tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
if (vdir.SkipCertValidations){
tlsIcon = `<i class="yellow lock icon" title="TLS/SSL mode without verification"></i>`
}
} }
let tlsVerificationField = ""; let tlsVerificationField = "";
@ -55,7 +57,6 @@
$("#vdirList").append(`<tr eptuuid="${vdir.RootOrMatchingDomain}" payload="${vdirData}" class="vdirEntry"> $("#vdirList").append(`<tr eptuuid="${vdir.RootOrMatchingDomain}" payload="${vdirData}" class="vdirEntry">
<td data-label="" editable="false">${vdir.RootOrMatchingDomain}</td> <td data-label="" editable="false">${vdir.RootOrMatchingDomain}</td>
<td data-label="" editable="true" datatype="domain">${vdir.Domain} ${tlsIcon}</td> <td data-label="" editable="true" datatype="domain">${vdir.Domain} ${tlsIcon}</td>
<td data-label="" editable="true" datatype="skipver">${tlsVerificationField}</td>
<td data-label="" editable="true" datatype="basicauth">${vdir.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td> <td data-label="" editable="true" datatype="basicauth">${vdir.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td>
<td class="center aligned" editable="true" datatype="action" data-label=""> <td class="center aligned" editable="true" datatype="action" data-label="">
<button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("vdir","${vdir.RootOrMatchingDomain}")'><i class="edit icon"></i></button> <button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("vdir","${vdir.RootOrMatchingDomain}")'><i class="edit icon"></i></button>

View File

@ -17,7 +17,7 @@
<h3>Web Server Settings</h3> <h3>Web Server Settings</h3>
<div class="ui form"> <div class="ui form">
<div class="inline field"> <div class="inline field">
<div class="ui toggle checkbox"> <div class="ui toggle checkbox webservRootDisabled">
<input id="webserv_enable" type="checkbox" class="hidden"> <input id="webserv_enable" type="checkbox" class="hidden">
<label>Enable Static Web Server</label> <label>Enable Static Web Server</label>
</div> </div>
@ -37,7 +37,7 @@
See the -webserv flag for more details. See the -webserv flag for more details.
</small> </small>
</div> </div>
<div class="field"> <div class="field webservRootDisabled">
<label>Port Number</label> <label>Port Number</label>
<input id="webserv_listenPort" type="number" step="1" min="0" max="65535" value="8081" onchange="updateWebServLinkExample(this.value);"> <input id="webserv_listenPort" type="number" step="1" min="0" max="65535" value="8081" onchange="updateWebServLinkExample(this.value);">
<small>Use <code>http://127.0.0.1:<span class="webserv_port">8081</span></code> in proxy rules to access the web server</small> <small>Use <code>http://127.0.0.1:<span class="webserv_port">8081</span></code> in proxy rules to access the web server</small>

View File

@ -19,7 +19,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -104,6 +103,20 @@ func HandleCountryDistrSummary(w http.ResponseWriter, r *http.Request) {
/* /*
Up Time Monitor Up Time Monitor
*/ */
// Update uptime monitor targets after rules updated
// See https://github.com/tobychui/zoraxy/issues/77
func UpdateUptimeMonitorTargets() {
if uptimeMonitor != nil {
uptimeMonitor.Config.Targets = GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter)
go func() {
uptimeMonitor.ExecuteUptimeCheck()
}()
SystemWideLogger.PrintAndLog("Uptime", "Uptime monitor config updated", nil)
}
}
// Generate uptime monitor targets from reverse proxy rules // Generate uptime monitor targets from reverse proxy rules
func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Target { func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Target {
subds := dp.GetSDProxyEndpointsAsMap() subds := dp.GetSDProxyEndpointsAsMap()
@ -263,7 +276,7 @@ func HandleWakeOnLan(w http.ResponseWriter, r *http.Request) {
return return
} }
log.Println("[WoL] Sending Wake on LAN magic packet to " + wake) SystemWideLogger.PrintAndLog("WoL", "Sending Wake on LAN magic packet to "+wake, nil)
err := wakeonlan.WakeTarget(wake) err := wakeonlan.WakeTarget(wake)
if err != nil { if err != nil {
utils.SendErrorResponse(w, err.Error()) utils.SendErrorResponse(w, err.Error())