diff --git a/src/accesslist.go b/src/accesslist.go
index a52d878..f3366d9 100644
--- a/src/accesslist.go
+++ b/src/accesslist.go
@@ -4,7 +4,7 @@ import (
"encoding/json"
"net/http"
- strip "github.com/grokify/html-strip-tags-go"
+ "github.com/microcosm-cc/bluemonday"
"imuslab.com/zoraxy/mod/geodb"
"imuslab.com/zoraxy/mod/utils"
)
@@ -137,7 +137,8 @@ func handleCountryWhitelistAdd(w http.ResponseWriter, r *http.Request) {
}
comment, _ := utils.PostPara(r, "comment")
- comment = strip.StripTags(comment)
+ p := bluemonday.StrictPolicy()
+ comment = p.Sanitize(comment)
geodbStore.AddCountryCodeToWhitelist(countryCode, comment)
@@ -164,7 +165,8 @@ func handleIpWhitelistAdd(w http.ResponseWriter, r *http.Request) {
}
comment, _ := utils.PostPara(r, "comment")
- comment = strip.StripTags(comment)
+ p := bluemonday.StrictPolicy()
+ comment = p.Sanitize(comment)
geodbStore.AddIPToWhiteList(ipAddr, comment)
}
diff --git a/src/api.go b/src/api.go
index 14df881..458a002 100644
--- a/src/api.go
+++ b/src/api.go
@@ -163,6 +163,8 @@ func initAPIs() {
authRouter.HandleFunc("/api/tools/smtp/set", HandleSMTPSet)
authRouter.HandleFunc("/api/tools/smtp/admin", HandleAdminEmailGet)
authRouter.HandleFunc("/api/tools/smtp/test", HandleTestEmailSend)
+ authRouter.HandleFunc("/api/tools/fwdproxy/enable", forwardProxy.HandleToogle)
+ authRouter.HandleFunc("/api/tools/fwdproxy/port", forwardProxy.HandlePort)
//Account Reset
http.HandleFunc("/api/account/reset", HandleAdminAccountResetEmail)
diff --git a/src/go.mod b/src/go.mod
index ce1c3b7..f07b4e5 100644
--- a/src/go.mod
+++ b/src/go.mod
@@ -10,11 +10,10 @@ require (
github.com/gorilla/sessions v1.2.1
github.com/gorilla/websocket v1.5.0
github.com/grandcat/zeroconf v1.0.0
- github.com/grokify/html-strip-tags-go v0.1.0
github.com/likexian/whois v1.15.1
github.com/microcosm-cc/bluemonday v1.0.25
- golang.org/x/net v0.14.0
- golang.org/x/sys v0.11.0
- golang.org/x/text v0.12.0
+ golang.org/x/net v0.20.0
+ golang.org/x/sys v0.16.0
+ golang.org/x/text v0.14.0
golang.org/x/tools v0.12.0 // indirect
)
diff --git a/src/go.sum b/src/go.sum
index cad7eab..d73f2bc 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -740,8 +740,6 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grandcat/zeroconf v1.0.0 h1:uHhahLBKqwWBV6WZUDAT71044vwOTL+McW0mBJvo6kE=
github.com/grandcat/zeroconf v1.0.0/go.mod h1:lTKmG1zh86XyCoUeIHSA4FJMBwCJiQmGfcP2PdzytEs=
-github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
-github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -1146,8 +1144,9 @@ golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
-golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
+golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
+golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1268,8 +1267,9 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
-golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
+golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1421,8 +1421,9 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1437,6 +1438,7 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
+golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1455,8 +1457,9 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/src/main.go b/src/main.go
index d8be86f..263334c 100644
--- a/src/main.go
+++ b/src/main.go
@@ -17,6 +17,7 @@ import (
"imuslab.com/zoraxy/mod/database"
"imuslab.com/zoraxy/mod/dynamicproxy/redirection"
"imuslab.com/zoraxy/mod/email"
+ "imuslab.com/zoraxy/mod/forwardproxy"
"imuslab.com/zoraxy/mod/ganserv"
"imuslab.com/zoraxy/mod/geodb"
"imuslab.com/zoraxy/mod/info/logger"
@@ -49,9 +50,9 @@ var logOutputToFile = flag.Bool("log", true, "Log terminal output to file")
var (
name = "Zoraxy"
- version = "3.0.0"
+ version = "3.0.1"
nodeUUID = "generic"
- development = false //Set this to false to use embedded web fs
+ development = true //Set this to false to use embedded web fs
bootTime = time.Now().Unix()
/*
@@ -79,6 +80,7 @@ var (
acmeHandler *acme.ACMEHandler //Handler for ACME Certificate renew
acmeAutoRenewer *acme.AutoRenewer //Handler for ACME auto renew ticking
staticWebServer *webserv.WebServer //Static web server for hosting simple stuffs
+ forwardProxy *forwardproxy.Handler //HTTP Forward proxy, basically VPN for web browser
//Helper modules
EmailSender *email.Sender //Email sender that handle email sending
diff --git a/src/mod/dynamicproxy/dpcore/dpcore.go b/src/mod/dynamicproxy/dpcore/dpcore.go
index 321f031..8b70556 100644
--- a/src/mod/dynamicproxy/dpcore/dpcore.go
+++ b/src/mod/dynamicproxy/dpcore/dpcore.go
@@ -272,6 +272,14 @@ func removeHeaders(header http.Header, noCache bool) {
header.Del("Cache-Control")
header.Set("Cache-Control", "no-store")
}
+
+ //Hide Go-HTTP-Client UA if the client didnt sent us one
+ if _, ok := header["User-Agent"]; !ok {
+ // If the outbound request doesn't have a User-Agent header set,
+ // don't send the default Go HTTP client User-Agent.
+ header.Set("User-Agent", "")
+ }
+
}
func addXForwardedForHeader(req *http.Request) {
@@ -365,6 +373,12 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
}
}
+ //if res.StatusCode == 501 || res.StatusCode == 500 {
+ // fmt.Println(outreq.Proto, outreq.RemoteAddr, outreq.RequestURI)
+ // fmt.Println(">>>", outreq.Method, res.Header, res.ContentLength, res.StatusCode)
+ // fmt.Println(outreq.Header, req.Host)
+ //}
+
//Custom header rewriter functions
if res.Header.Get("Location") != "" {
locationRewrite := res.Header.Get("Location")
diff --git a/src/mod/dynamicproxy/proxyRequestHandler.go b/src/mod/dynamicproxy/proxyRequestHandler.go
index d1e5bfc..5193d07 100644
--- a/src/mod/dynamicproxy/proxyRequestHandler.go
+++ b/src/mod/dynamicproxy/proxyRequestHandler.go
@@ -114,7 +114,10 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
u, _ = url.Parse("wss://" + wsRedirectionEndpoint + requestURL)
}
h.logRequest(r, true, 101, "subdomain-websocket", target.Domain)
- wspHandler := websocketproxy.NewProxy(u, target.SkipCertValidations)
+ wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
+ SkipTLSValidation: target.SkipCertValidations,
+ SkipOriginCheck: target.SkipWebSocketOriginCheck,
+ })
wspHandler.ServeHTTP(w, r)
return
}
@@ -178,7 +181,10 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
u, _ = url.Parse("wss://" + wsRedirectionEndpoint + r.URL.String())
}
h.logRequest(r, true, 101, "vdir-websocket", target.Domain)
- wspHandler := websocketproxy.NewProxy(u, target.SkipCertValidations)
+ wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
+ SkipTLSValidation: target.SkipCertValidations,
+ SkipOriginCheck: target.parent.SkipWebSocketOriginCheck,
+ })
wspHandler.ServeHTTP(w, r)
return
}
diff --git a/src/mod/dynamicproxy/typedef.go b/src/mod/dynamicproxy/typedef.go
index 0a48e33..d67b808 100644
--- a/src/mod/dynamicproxy/typedef.go
+++ b/src/mod/dynamicproxy/typedef.go
@@ -95,9 +95,10 @@ type ProxyEndpoint struct {
Domain string //Domain or IP to proxy to
//TLS/SSL Related
- RequireTLS bool //Target domain require TLS
- BypassGlobalTLS bool //Bypass global TLS setting options if TLS Listener enabled (parent.tlsListener != nil)
- SkipCertValidations bool //Set to true to accept self signed certs
+ RequireTLS bool //Target domain require TLS
+ BypassGlobalTLS bool //Bypass global TLS setting options if TLS Listener enabled (parent.tlsListener != nil)
+ SkipCertValidations bool //Set to true to accept self signed certs
+ SkipWebSocketOriginCheck bool //Skip origin check on websocket upgrade connections
//Virtual Directories
VirtualDirectories []*VirtualDirectoryEndpoint
@@ -115,6 +116,7 @@ type ProxyEndpoint struct {
DefaultSiteValue string //Fallback routing target, optional
Disabled bool //If the rule is disabled
+
//Internal Logic Elements
parent *Router
proxy *dpcore.ReverseProxy `json:"-"`
diff --git a/src/mod/forwardproxy/cproxy/LICENSE.md b/src/mod/forwardproxy/cproxy/LICENSE.md
new file mode 100644
index 0000000..99ce426
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/LICENSE.md
@@ -0,0 +1,25 @@
+MIT License
+
+Copyright (c) 2022 Smarty
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+NOTE: Various optional and subordinate components carry their own licensing
+requirements and restrictions. Use of those components is subject to the terms
+and conditions outlined the respective license of each component.
diff --git a/src/mod/forwardproxy/cproxy/config.go b/src/mod/forwardproxy/cproxy/config.go
new file mode 100644
index 0000000..f0d82bf
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/config.go
@@ -0,0 +1,109 @@
+package cproxy
+
+import (
+ "net/http"
+ "time"
+)
+
+func New(options ...option) http.Handler {
+ var this configuration
+ Options.apply(options...)(&this)
+ return newHandler(this.Filter, this.ClientConnector, this.ServerConnector, this.Monitor)
+}
+
+var Options singleton
+
+type singleton struct{}
+type option func(*configuration)
+
+type configuration struct {
+ DialTimeout time.Duration
+ Filter Filter
+ DialAddress string
+ Dialer Dialer
+ LogConnections bool
+ ProxyProtocol bool
+ Initializer initializer
+ ClientConnector clientConnector
+ ServerConnector serverConnector
+ Monitor monitor
+ Logger logger
+}
+
+func (singleton) DialTimeout(value time.Duration) option {
+ return func(this *configuration) { this.DialTimeout = value }
+}
+func (singleton) Filter(value Filter) option {
+ return func(this *configuration) { this.Filter = value }
+}
+func (singleton) ClientConnector(value clientConnector) option {
+ return func(this *configuration) { this.ClientConnector = value }
+}
+func (singleton) DialAddress(value string) option {
+ return func(this *configuration) { this.DialAddress = value }
+}
+func (singleton) Dialer(value Dialer) option {
+ return func(this *configuration) { this.Dialer = value }
+}
+func (singleton) LogConnections(value bool) option {
+ return func(this *configuration) { this.LogConnections = value }
+}
+func (singleton) ProxyProtocol(value bool) option {
+ return func(this *configuration) { this.ProxyProtocol = value }
+}
+func (singleton) Initializer(value initializer) option {
+ return func(this *configuration) { this.Initializer = value }
+}
+func (singleton) ServerConnector(value serverConnector) option {
+ return func(this *configuration) { this.ServerConnector = value }
+}
+func (singleton) Monitor(value monitor) option {
+ return func(this *configuration) { this.Monitor = value }
+}
+func (singleton) Logger(value logger) option {
+ return func(this *configuration) { this.Logger = value }
+}
+
+func (singleton) apply(options ...option) option {
+ return func(this *configuration) {
+ for _, item := range Options.defaults(options...) {
+ item(this)
+ }
+
+ if this.Dialer == nil {
+ this.Dialer = newDialer(this)
+ }
+
+ this.Dialer = newRoutingDialer(this)
+
+ if this.ProxyProtocol {
+ this.Initializer = newProxyProtocolInitializer()
+ }
+
+ if this.Initializer == nil {
+ this.Initializer = nop{}
+ }
+
+ this.Initializer = newLoggingInitializer(this)
+
+ if this.ServerConnector == nil {
+ this.ServerConnector = newServerConnector(this.Dialer, this.Initializer)
+ }
+ }
+}
+func (singleton) defaults(options ...option) []option {
+ return append([]option{
+ Options.DialTimeout(time.Second * 10),
+ Options.Filter(newFilter()),
+ Options.ClientConnector(newClientConnector()),
+ Options.Initializer(nop{}),
+ Options.Monitor(nop{}),
+ Options.Logger(nop{}),
+ }, options...)
+}
+
+type nop struct{}
+
+func (nop) Measure(int) {}
+func (nop) Printf(string, ...interface{}) {}
+func (nop) Initialize(Socket, Socket) bool { return true }
diff --git a/src/mod/forwardproxy/cproxy/default_client_connector.go b/src/mod/forwardproxy/cproxy/default_client_connector.go
new file mode 100644
index 0000000..6fd284d
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/default_client_connector.go
@@ -0,0 +1,19 @@
+package cproxy
+
+import "net/http"
+
+type defaultClientConnector struct{}
+
+func newClientConnector() *defaultClientConnector {
+ return &defaultClientConnector{}
+}
+
+func (this *defaultClientConnector) Connect(response http.ResponseWriter) Socket {
+ if hijacker, ok := response.(http.Hijacker); !ok {
+ return nil
+ } else if socket, _, _ := hijacker.Hijack(); socket == nil {
+ return nil // this 'else if' exists to avoid the pointer nil != interface nil issue
+ } else {
+ return socket
+ }
+}
diff --git a/src/mod/forwardproxy/cproxy/default_dialer.go b/src/mod/forwardproxy/cproxy/default_dialer.go
new file mode 100644
index 0000000..dce5da2
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/default_dialer.go
@@ -0,0 +1,25 @@
+package cproxy
+
+import (
+ "net"
+ "time"
+)
+
+type defaultDialer struct {
+ timeout time.Duration
+ logger logger
+}
+
+func newDialer(config *configuration) *defaultDialer {
+ return &defaultDialer{timeout: config.DialTimeout, logger: config.Logger}
+}
+
+func (this *defaultDialer) Dial(address string) Socket {
+ if socket, err := net.DialTimeout("tcp", address, this.timeout); err == nil {
+ return socket
+ } else {
+ this.logger.Printf("[INFO] Unable to establish connection to [%s]: %s", address, err)
+ }
+
+ return nil
+}
diff --git a/src/mod/forwardproxy/cproxy/default_filter.go b/src/mod/forwardproxy/cproxy/default_filter.go
new file mode 100644
index 0000000..bbee349
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/default_filter.go
@@ -0,0 +1,9 @@
+package cproxy
+
+import "net/http"
+
+type defaultFilter struct{}
+
+func newFilter() *defaultFilter { return &defaultFilter{} }
+
+func (this *defaultFilter) IsAuthorized(http.ResponseWriter, *http.Request) bool { return true }
diff --git a/src/mod/forwardproxy/cproxy/default_handler.go b/src/mod/forwardproxy/cproxy/default_handler.go
new file mode 100644
index 0000000..a5e72d2
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/default_handler.go
@@ -0,0 +1,56 @@
+package cproxy
+
+import "net/http"
+
+type defaultHandler struct {
+ filter Filter
+ clientConnector clientConnector
+ serverConnector serverConnector
+ meter monitor
+}
+
+func newHandler(filter Filter, clientConnector clientConnector, serverConnector serverConnector, meter monitor) *defaultHandler {
+ return &defaultHandler{
+ filter: filter,
+ clientConnector: clientConnector,
+ serverConnector: serverConnector,
+ meter: meter,
+ }
+}
+
+func (this *defaultHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
+ this.meter.Measure(MeasurementHTTPRequest)
+
+ if request.Method != "CONNECT" {
+ this.meter.Measure(MeasurementBadMethod)
+ writeResponseStatus(response, http.StatusMethodNotAllowed)
+
+ } else if !this.filter.IsAuthorized(response, request) {
+ this.meter.Measure(MeasurementUnauthorizedRequest)
+ //writeResponseStatus(response, http.StatusUnauthorized)
+
+ } else if client := this.clientConnector.Connect(response); client == nil {
+ this.meter.Measure(MeasurementClientConnectionFailed)
+ writeResponseStatus(response, http.StatusNotImplemented)
+
+ } else if connection := this.serverConnector.Connect(client, request.URL.Host); connection == nil {
+ this.meter.Measure(MeasurementServerConnectionFailed)
+ _, _ = client.Write(statusBadGateway)
+ _ = client.Close()
+
+ } else {
+ this.meter.Measure(MeasurementProxyReady)
+ _, _ = client.Write(statusReady)
+ connection.Proxy()
+ this.meter.Measure(MeasurementProxyComplete)
+ }
+}
+
+func writeResponseStatus(response http.ResponseWriter, statusCode int) {
+ http.Error(response, http.StatusText(statusCode), statusCode)
+}
+
+var (
+ statusBadGateway = []byte("HTTP/1.1 502 Bad Gateway\r\n\r\n")
+ statusReady = []byte("HTTP/1.1 200 OK\r\n\r\n")
+)
diff --git a/src/mod/forwardproxy/cproxy/default_proxy.go b/src/mod/forwardproxy/cproxy/default_proxy.go
new file mode 100644
index 0000000..99b3663
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/default_proxy.go
@@ -0,0 +1,54 @@
+package cproxy
+
+import (
+ "io"
+ "sync"
+)
+
+type defaultProxy struct {
+ client Socket
+ server Socket
+ waiter *sync.WaitGroup
+}
+
+func newProxy(client, server Socket) *defaultProxy {
+ waiter := &sync.WaitGroup{}
+ waiter.Add(2) // wait on both client->server and server->client streams
+
+ return &defaultProxy{
+ waiter: waiter,
+ client: client,
+ server: server,
+ }
+}
+
+func (this *defaultProxy) Proxy() {
+ go this.streamAndClose(this.client, this.server)
+ go this.streamAndClose(this.server, this.client)
+ this.closeSockets()
+}
+
+func (this *defaultProxy) streamAndClose(reader, writer Socket) {
+ _, _ = io.Copy(writer, reader)
+
+ tryCloseRead(reader)
+ tryCloseWrite(writer)
+
+ this.waiter.Done()
+}
+func tryCloseRead(socket Socket) {
+ if tcp, ok := socket.(tcpSocket); ok {
+ _ = tcp.CloseRead()
+ }
+}
+func tryCloseWrite(socket Socket) {
+ if tcp, ok := socket.(tcpSocket); ok {
+ _ = tcp.CloseWrite()
+ }
+}
+
+func (this *defaultProxy) closeSockets() {
+ this.waiter.Wait()
+ _ = this.client.Close()
+ _ = this.server.Close()
+}
diff --git a/src/mod/forwardproxy/cproxy/default_server_connector.go b/src/mod/forwardproxy/cproxy/default_server_connector.go
new file mode 100644
index 0000000..a934f15
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/default_server_connector.go
@@ -0,0 +1,24 @@
+package cproxy
+
+type defaultServerConnector struct {
+ dialer Dialer
+ initializer initializer
+}
+
+func newServerConnector(dialer Dialer, initializer initializer) *defaultServerConnector {
+ return &defaultServerConnector{dialer: dialer, initializer: initializer}
+}
+
+func (this *defaultServerConnector) Connect(client Socket, serverAddress string) proxy {
+ server := this.dialer.Dial(serverAddress)
+ if server == nil {
+ return nil
+ }
+
+ if !this.initializer.Initialize(client, server) {
+ _ = server.Close()
+ return nil
+ }
+
+ return newProxy(client, server)
+}
diff --git a/src/mod/forwardproxy/cproxy/hostname_filter.go b/src/mod/forwardproxy/cproxy/hostname_filter.go
new file mode 100644
index 0000000..fb0476c
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/hostname_filter.go
@@ -0,0 +1,32 @@
+package cproxy
+
+import "net/http"
+
+type hostnameFilter struct {
+ authorized []string
+}
+
+func NewHostnameFilter(authorized []string) Filter {
+ return &hostnameFilter{authorized: authorized}
+}
+
+func (this hostnameFilter) IsAuthorized(_ http.ResponseWriter, request *http.Request) bool {
+ if len(this.authorized) == 0 {
+ return true
+ }
+
+ host := request.URL.Host
+ hostLength := len(host)
+ for _, authorized := range this.authorized {
+ if authorized[:2] == "*." {
+ have, want := hostLength, len(authorized)-1
+ if have > want && authorized[1:] == host[hostLength-want:] {
+ return true
+ }
+ } else if authorized == host {
+ return true
+ }
+ }
+
+ return false
+}
diff --git a/src/mod/forwardproxy/cproxy/hostname_suffix_filter.go b/src/mod/forwardproxy/cproxy/hostname_suffix_filter.go
new file mode 100644
index 0000000..9c3652d
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/hostname_suffix_filter.go
@@ -0,0 +1,26 @@
+package cproxy
+
+import (
+ "net/http"
+ "strings"
+)
+
+type hostnameSuffixFilter struct {
+ authorized []string
+}
+
+func NewHostnameSuffixFilter(authorized []string) Filter {
+ return &hostnameSuffixFilter{authorized: authorized}
+}
+
+func (this hostnameSuffixFilter) IsAuthorized(_ http.ResponseWriter, request *http.Request) bool {
+ host := request.URL.Host
+
+ for _, authorized := range this.authorized {
+ if strings.HasSuffix(host, authorized) {
+ return true
+ }
+ }
+
+ return false
+}
diff --git a/src/mod/forwardproxy/cproxy/interfaces.go b/src/mod/forwardproxy/cproxy/interfaces.go
new file mode 100644
index 0000000..1ed0093
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/interfaces.go
@@ -0,0 +1,67 @@
+package cproxy
+
+import (
+ "io"
+ "net"
+ "net/http"
+)
+
+type (
+ Filter interface {
+ IsAuthorized(http.ResponseWriter, *http.Request) bool
+ }
+
+ clientConnector interface {
+ Connect(http.ResponseWriter) Socket
+ }
+)
+
+type (
+ Dialer interface {
+ Dial(string) Socket
+ }
+
+ serverConnector interface {
+ Connect(Socket, string) proxy
+ }
+
+ initializer interface {
+ Initialize(Socket, Socket) bool
+ }
+
+ proxy interface {
+ Proxy()
+ }
+)
+
+type (
+ Socket interface {
+ io.ReadWriteCloser
+ RemoteAddr() net.Addr
+ }
+
+ tcpSocket interface {
+ Socket
+ CloseRead() error
+ CloseWrite() error
+ }
+)
+
+type (
+ monitor interface {
+ Measure(int)
+ }
+ logger interface {
+ Printf(string, ...interface{})
+ }
+)
+
+const (
+ MeasurementHTTPRequest int = iota
+ MeasurementBadMethod
+ MeasurementUnauthorizedRequest
+ MeasurementClientConnectionFailed
+ MeasurementServerConnectionFailed
+ MeasurementProxyReady
+ MeasurementProxyComplete
+)
diff --git a/src/mod/forwardproxy/cproxy/logging_initializer.go b/src/mod/forwardproxy/cproxy/logging_initializer.go
new file mode 100644
index 0000000..37d5d72
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/logging_initializer.go
@@ -0,0 +1,24 @@
+package cproxy
+
+type loggingInitializer struct {
+ logger logger
+ inner initializer
+}
+
+func newLoggingInitializer(config *configuration) initializer {
+ if !config.LogConnections {
+ return config.Initializer
+ }
+
+ return &loggingInitializer{inner: config.Initializer, logger: config.Logger}
+}
+
+func (this *loggingInitializer) Initialize(client, server Socket) bool {
+ result := this.inner.Initialize(client, server)
+
+ if !result {
+ this.logger.Printf("[INFO] Connection failed [%s] -> [%s]", client.RemoteAddr(), server.RemoteAddr())
+ }
+
+ return result
+}
diff --git a/src/mod/forwardproxy/cproxy/proxy_protocol_initializer.go b/src/mod/forwardproxy/cproxy/proxy_protocol_initializer.go
new file mode 100644
index 0000000..df65ca2
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/proxy_protocol_initializer.go
@@ -0,0 +1,36 @@
+package cproxy
+
+import (
+ "fmt"
+ "io"
+ "net"
+ "strings"
+)
+
+type proxyProtocolInitializer struct{}
+
+func newProxyProtocolInitializer() *proxyProtocolInitializer {
+ return &proxyProtocolInitializer{}
+}
+
+func (this *proxyProtocolInitializer) Initialize(client, server Socket) bool {
+ header := formatHeader(client.RemoteAddr(), server.RemoteAddr())
+ _, err := io.WriteString(server, header)
+ return err == nil
+}
+func formatHeader(client, server net.Addr) string {
+ clientAddress, clientPort := parseAddress(client.String())
+ serverAddress, serverPort := parseAddress(server.String())
+ if strings.Contains(clientAddress, ":") {
+ return fmt.Sprintf(proxyProtocolIPv6Preamble, clientAddress, serverAddress, clientPort, serverPort)
+ }
+
+ return fmt.Sprintf(proxyProtocolIPv4Preamble, clientAddress, serverAddress, clientPort, serverPort)
+}
+func parseAddress(address string) (string, string) {
+ address, port, _ := net.SplitHostPort(address)
+ return address, port
+}
+
+const proxyProtocolIPv4Preamble = "PROXY TCP4 %s %s %s %s\r\n"
+const proxyProtocolIPv6Preamble = "PROXY TCP6 %s %s %s %s\r\n"
diff --git a/src/mod/forwardproxy/cproxy/routing_dialer.go b/src/mod/forwardproxy/cproxy/routing_dialer.go
new file mode 100644
index 0000000..6e2a893
--- /dev/null
+++ b/src/mod/forwardproxy/cproxy/routing_dialer.go
@@ -0,0 +1,18 @@
+package cproxy
+
+type routingDialer struct {
+ inner Dialer
+ targetAddress string
+}
+
+func newRoutingDialer(config *configuration) Dialer {
+ if len(config.DialAddress) == 0 {
+ return config.Dialer
+ }
+
+ return &routingDialer{inner: config.Dialer, targetAddress: config.DialAddress}
+}
+
+func (this *routingDialer) Dial(string) Socket {
+ return this.inner.Dial(this.targetAddress)
+}
diff --git a/src/mod/forwardproxy/forwardproxy.go b/src/mod/forwardproxy/forwardproxy.go
new file mode 100644
index 0000000..7213983
--- /dev/null
+++ b/src/mod/forwardproxy/forwardproxy.go
@@ -0,0 +1,137 @@
+package forwardproxy
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "log"
+ "net/http"
+ "strconv"
+ "time"
+
+ "imuslab.com/zoraxy/mod/database"
+ "imuslab.com/zoraxy/mod/forwardproxy/cproxy"
+ "imuslab.com/zoraxy/mod/info/logger"
+ "imuslab.com/zoraxy/mod/utils"
+)
+
+type ZrFilter struct {
+ //To be implemented
+}
+
+type Handler struct {
+ server *http.Server
+ handler *http.Handler
+ running bool
+ db *database.Database
+ logger *logger.Logger
+ Port int
+}
+
+func NewForwardProxy(sysdb *database.Database, port int, logger *logger.Logger) *Handler {
+ thisFilter := ZrFilter{}
+ handler := cproxy.New(cproxy.Options.Filter(thisFilter))
+
+ return &Handler{
+ db: sysdb,
+ server: nil,
+ handler: &handler,
+ running: false,
+ logger: logger,
+ Port: port,
+ }
+}
+
+// Start the forward proxy
+func (h *Handler) Start() error {
+ if h.running {
+ return errors.New("forward proxy already running")
+ }
+ server := &http.Server{Addr: ":" + strconv.Itoa(h.Port), Handler: *h.handler}
+ h.server = server
+
+ go func() {
+ if err := server.ListenAndServe(); err != nil {
+ if err != nil {
+ log.Println(err.Error())
+ }
+ }
+ }()
+
+ h.running = true
+ return nil
+}
+
+// Stop the forward proxy
+func (h *Handler) Stop() error {
+ if h.running && h.server != nil {
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+ if err := h.server.Shutdown(ctx); err != nil {
+ return err
+ }
+ h.running = false
+ h.server = nil
+ }
+ return nil
+}
+
+// Update the port number of the forward proxy
+func (h *Handler) UpdatePort(newPort int) error {
+ h.Stop()
+ h.Port = newPort
+ return h.Start()
+}
+
+func (it ZrFilter) IsAuthorized(w http.ResponseWriter, r *http.Request) bool {
+ return true
+}
+
+// Handle port change of the forward proxy
+func (h *Handler) HandlePort(w http.ResponseWriter, r *http.Request) {
+ port, err := utils.PostInt(r, "port")
+ if err != nil {
+ js, _ := json.Marshal(h.Port)
+ utils.SendJSONResponse(w, string(js))
+ } else {
+ //Update the port
+ err = h.UpdatePort(port)
+ if err != nil {
+ utils.SendErrorResponse(w, err.Error())
+ return
+ }
+ h.logger.PrintAndLog("Forward Proxy", "HTTP Forward Proxy port updated to :"+strconv.Itoa(h.Port), nil)
+ h.db.Write("fwdproxy", "port", port)
+ utils.SendOK(w)
+ }
+}
+
+// Handle power toggle of the forward proxys
+func (h *Handler) HandleToogle(w http.ResponseWriter, r *http.Request) {
+ enabled, err := utils.PostBool(r, "enable")
+ if err != nil {
+ //Get the current state of the forward proxy
+ js, _ := json.Marshal(h.running)
+ utils.SendJSONResponse(w, string(js))
+ } else {
+ if enabled {
+ err = h.Start()
+ if err != nil {
+ h.logger.PrintAndLog("Forward Proxy", "Unable to start forward proxy server", err)
+ utils.SendErrorResponse(w, err.Error())
+ return
+ }
+ h.logger.PrintAndLog("Forward Proxy", "HTTP Forward Proxy Started, listening on :"+strconv.Itoa(h.Port), nil)
+ } else {
+ err = h.Stop()
+ if err != nil {
+ h.logger.PrintAndLog("Forward Proxy", "Unable to stop forward proxy server", err)
+ utils.SendErrorResponse(w, err.Error())
+ return
+ }
+ h.logger.PrintAndLog("Forward Proxy", "HTTP Forward Proxy Stopped", nil)
+ }
+ h.db.Write("fwdproxy", "enabled", enabled)
+ utils.SendOK(w)
+ }
+}
diff --git a/src/mod/sshprox/sshprox.go b/src/mod/sshprox/sshprox.go
index 429013c..de96764 100644
--- a/src/mod/sshprox/sshprox.go
+++ b/src/mod/sshprox/sshprox.go
@@ -85,7 +85,10 @@ func (m *Manager) HandleHttpByInstanceId(instanceId string, w http.ResponseWrite
r.Header.Set("Zr-Origin-Upgrade", "websocket")
requestURL = strings.TrimPrefix(requestURL, "/")
u, _ := url.Parse("ws://127.0.0.1:" + strconv.Itoa(targetInstance.AssignedPort) + "/" + requestURL)
- wspHandler := websocketproxy.NewProxy(u, false)
+ wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{
+ SkipTLSValidation: false,
+ SkipOriginCheck: false,
+ })
wspHandler.ServeHTTP(w, r)
return
}
diff --git a/src/mod/websocketproxy/websocketproxy.go b/src/mod/websocketproxy/websocketproxy.go
index c27b3dd..54ab7eb 100644
--- a/src/mod/websocketproxy/websocketproxy.go
+++ b/src/mod/websocketproxy/websocketproxy.go
@@ -47,19 +47,26 @@ type WebsocketProxy struct {
// If nil, DefaultDialer is used.
Dialer *websocket.Dialer
- Verbal bool
- SkipTlsValidation bool
+ Verbal bool
+
+ Options Options
+}
+
+// Additional options for websocket proxy runtime
+type Options struct {
+ SkipTLSValidation bool //Skip backend TLS validation
+ SkipOriginCheck bool //Skip origin check
}
// ProxyHandler returns a new http.Handler interface that reverse proxies the
// request to the given target.
-func ProxyHandler(target *url.URL, skipTlsValidation bool) http.Handler {
- return NewProxy(target, skipTlsValidation)
+func ProxyHandler(target *url.URL, options Options) http.Handler {
+ return NewProxy(target, options)
}
// NewProxy returns a new Websocket reverse proxy that rewrites the
// URL's to the scheme, host and base path provider in target.
-func NewProxy(target *url.URL, skipTlsValidation bool) *WebsocketProxy {
+func NewProxy(target *url.URL, options Options) *WebsocketProxy {
backend := func(r *http.Request) *url.URL {
// Shallow copy
u := *target
@@ -68,7 +75,7 @@ func NewProxy(target *url.URL, skipTlsValidation bool) *WebsocketProxy {
u.RawQuery = r.URL.RawQuery
return &u
}
- return &WebsocketProxy{Backend: backend, Verbal: false, SkipTlsValidation: skipTlsValidation}
+ return &WebsocketProxy{Backend: backend, Verbal: false, Options: options}
}
// ServeHTTP implements the http.Handler that proxies WebSocket connections.
@@ -88,7 +95,7 @@ func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
dialer := w.Dialer
if w.Dialer == nil {
- if w.SkipTlsValidation {
+ if w.Options.SkipTLSValidation {
//Disable TLS secure check if target allow skip verification
bypassDialer := websocket.DefaultDialer
bypassDialer.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
@@ -171,6 +178,13 @@ func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
upgrader = DefaultUpgrader
}
+ //Fixing issue #107 by bypassing request origin check
+ if w.Options.SkipOriginCheck {
+ upgrader.CheckOrigin = func(r *http.Request) bool {
+ return true
+ }
+ }
+
// Only pass those headers to the upgrader.
upgradeHeader := http.Header{}
if hdr := resp.Header.Get("Sec-Websocket-Protocol"); hdr != "" {
diff --git a/src/mod/websocketproxy/websocketproxy_test.go b/src/mod/websocketproxy/websocketproxy_test.go
index 6059261..20c4668 100644
--- a/src/mod/websocketproxy/websocketproxy_test.go
+++ b/src/mod/websocketproxy/websocketproxy_test.go
@@ -28,7 +28,10 @@ func TestProxy(t *testing.T) {
}
u, _ := url.Parse(backendURL)
- proxy := NewProxy(u, false)
+ proxy := NewProxy(u, Options{
+ SkipTLSValidation: false,
+ SkipOriginCheck: false,
+ })
proxy.Upgrader = upgrader
mux := http.NewServeMux()
diff --git a/src/start.go b/src/start.go
index 20a60ed..f1bb2c6 100644
--- a/src/start.go
+++ b/src/start.go
@@ -12,6 +12,7 @@ import (
"imuslab.com/zoraxy/mod/auth"
"imuslab.com/zoraxy/mod/database"
"imuslab.com/zoraxy/mod/dynamicproxy/redirection"
+ "imuslab.com/zoraxy/mod/forwardproxy"
"imuslab.com/zoraxy/mod/ganserv"
"imuslab.com/zoraxy/mod/geodb"
"imuslab.com/zoraxy/mod/info/logger"
@@ -219,6 +220,18 @@ func startupSequence() {
//Create an analytic loader
AnalyticLoader = analytic.NewDataLoader(sysdb, statisticCollector)
+ //Create basic forward proxy
+ sysdb.NewTable("fwdproxy")
+ fwdProxyEnabled := false
+ fwdProxyPort := 5587
+ sysdb.Read("fwdproxy", "port", &fwdProxyPort)
+ sysdb.Read("fwdproxy", "enabled", &fwdProxyEnabled)
+ forwardProxy = forwardproxy.NewForwardProxy(sysdb, fwdProxyPort, SystemWideLogger)
+ if fwdProxyEnabled {
+ SystemWideLogger.PrintAndLog("Forward Proxy", "HTTP Forward Proxy Listening on :"+strconv.Itoa(forwardProxy.Port), nil)
+ forwardProxy.Start()
+ }
+
/*
ACME API
@@ -241,4 +254,5 @@ func finalSequence() {
//Inject routing rules
registerBuildInRoutingRules()
+
}
diff --git a/src/web/components/networktools.html b/src/web/components/networktools.html
index 74e0bd1..cc4ea71 100644
--- a/src/web/components/networktools.html
+++ b/src/web/components/networktools.html
@@ -84,7 +84,23 @@
Paste to Terminal Shift + Insert
-
+
Setup a basic HTTP forward proxy to access web server in another LAN
+ To enable forward proxy in your domain, add a proxy rule to 127.0.0.1:{selected_port}
Wake up a remote server by WOL Magic Packet or an IoT device
@@ -558,6 +574,68 @@ function renderWhoisDomainTable(jsonData) { } +//Forward Proxy +function initForwardProxyInfo(){ + $.get("/api/tools/fwdproxy/enable", function(data){ + if (data == true){ + //Disable the start btn + $("#forwardProxyButtons").find(".startBtn").addClass('disabled'); + $("#forwardProxyButtons").find(".stopBtn").removeClass('disabled'); + }else{ + $("#forwardProxyButtons").find(".startBtn").removeClass('disabled'); + $("#forwardProxyButtons").find(".stopBtn").addClass('disabled'); + } + }); + + $.get("/api/tools/fwdproxy/port", function(data){ + $("#forwardProxyPort").val(data); + }) +} +initForwardProxyInfo(); + +function toggleForwadProxy(enabled){ + $.ajax({ + url: "/api/tools/fwdproxy/enable", + method: "POST", + data: { + "enable": enabled + }, + success: function(data){ + if (data.error != undefined){ + msgbox(data.error, false); + }else{ + msgbox(`Forward proxy ${enabled?"enabled":"disabled"}`) + } + + initForwardProxyInfo(); + } + }) +} + +function updateForwardProxyPort(){ + let newPortNumber = $("#forwardProxyPort").val(); + if (newPortNumber < 1024 || newPortNumber > 65535){ + $("#newPortNumber").parent().addClass('error'); + }else{ + $("#newPortNumber").parent().removeClass('error'); + } + + $.ajax({ + url: "/api/tools/fwdproxy/port", + method: "POST", + data: { + "port": newPortNumber + }, + success: function(data){ + if (data.error != undefined){ + msgbox(data.error, false); + } + msgbox("Forward proxy port updated"); + initForwardProxyInfo(); + } + }); +} + diff --git a/src/web/components/utils.html b/src/web/components/utils.html index 00d56b0..9d84eab 100644 --- a/src/web/components/utils.html +++ b/src/web/components/utils.html @@ -4,12 +4,12 @@You might find these tools or information helpful when setting up your gateway server
-No experience with CIDR notations? Here are some tools you can use to make setting up easier.
Options related to system backup, migrate and restore.
@@ -175,7 +175,16 @@