Skip to content

Commit a728543

Browse files
authored
Merge pull request #522 from tobychui/v3.1.7
- Merged and added new tagging system for HTTP Proxy rules - Added inline editing for redirection rules - Added uptime monitor status dot detail info (now clickable) - Added close connection support to port 80 listener - Optimized port collision check on startup - Optimized dark theme color scheme (Free consultation by [3S Design studio](https://www.3sdesign.io/)) - Fixed capital letter rule unable to delete bug
2 parents d1e5581 + 693dba0 commit a728543

25 files changed

+34565
-28135
lines changed

.gitignore

+6-1
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ src/tmp/localhost.pem
3939
src/www/html/index.html
4040
src/sys.uuid
4141
src/zoraxy
42-
src/log/
42+
src/log/
43+
44+
45+
# dev-tags
46+
/Dockerfile
47+
/Entrypoint.sh

docker/entrypoint.sh

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
#!/usr/bin/env bash
22

3+
trap cleanup TERM INT
4+
5+
cleanup() {
6+
echo "Shutting down..."
7+
kill -TERM "$(pidof zoraxy)" &> /dev/null && echo "Zoraxy stopped."
8+
kill -TERM "$(pidof zerotier-one)" &> /dev/null && echo "ZeroTier-One stopped."
9+
exit 0
10+
}
11+
312
update-ca-certificates
413
echo "CA certificates updated."
514

@@ -11,12 +20,13 @@ if [ "$ZEROTIER" = "true" ]; then
1120
mkdir -p /opt/zoraxy/config/zerotier/
1221
fi
1322
ln -s /opt/zoraxy/config/zerotier/ /var/lib/zerotier-one
14-
zerotier-one -d
23+
zerotier-one -d &
24+
zerotierpid=$!
1525
echo "ZeroTier daemon started."
1626
fi
1727

1828
echo "Starting Zoraxy..."
19-
exec zoraxy \
29+
zoraxy \
2030
-autorenew="$AUTORENEW" \
2131
-cfgupgrade="$CFGUPGRADE" \
2232
-db="$DB" \
@@ -33,5 +43,10 @@ exec zoraxy \
3343
-webfm="$WEBFM" \
3444
-webroot="$WEBROOT" \
3545
-ztauth="$ZTAUTH" \
36-
-ztport="$ZTPORT"
46+
-ztport="$ZTPORT" \
47+
&
48+
49+
zoraxypid=$!
50+
wait $zoraxypid
51+
wait $zerotierpid
3752

src/api.go

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ func RegisterRedirectionAPIs(authRouter *auth.RouterDef) {
8888
authRouter.HandleFunc("/api/redirect/list", handleListRedirectionRules)
8989
authRouter.HandleFunc("/api/redirect/add", handleAddRedirectionRule)
9090
authRouter.HandleFunc("/api/redirect/delete", handleDeleteRedirectionRule)
91+
authRouter.HandleFunc("/api/redirect/edit", handleEditRedirectionRule)
9192
authRouter.HandleFunc("/api/redirect/regex", handleToggleRedirectRegexpSupport)
9293
}
9394

src/config.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ func LoadReverseProxyConfig(configFilepath string) error {
5454
return err
5555
}
5656

57+
//Make sure the tags are not nil
58+
if thisConfigEndpoint.Tags == nil {
59+
thisConfigEndpoint.Tags = []string{}
60+
}
61+
5762
//Matching domain not set. Assume root
5863
if thisConfigEndpoint.RootOrMatchingDomain == "" {
5964
thisConfigEndpoint.RootOrMatchingDomain = "/"
@@ -175,8 +180,8 @@ func ExportConfigAsZip(w http.ResponseWriter, r *http.Request) {
175180

176181
// Set the Content-Type header to indicate it's a zip file
177182
w.Header().Set("Content-Type", "application/zip")
178-
// Set the Content-Disposition header to specify the file name
179-
w.Header().Set("Content-Disposition", "attachment; filename=\"config.zip\"")
183+
// Set the Content-Disposition header to specify the file name, add timestamp to the filename
184+
w.Header().Set("Content-Disposition", "attachment; filename=\"zoraxy-config-"+time.Now().Format("2006-01-02-15-04-05")+".zip\"")
180185

181186
// Create a zip writer
182187
zipWriter := zip.NewWriter(w)

src/def.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import (
4242
const (
4343
/* Build Constants */
4444
SYSTEM_NAME = "Zoraxy"
45-
SYSTEM_VERSION = "3.1.6"
45+
SYSTEM_VERSION = "3.1.7"
4646
DEVELOPMENT_BUILD = false /* Development: Set to false to use embedded web fs */
4747

4848
/* System Constants */
@@ -87,6 +87,10 @@ var (
8787
allowWebFileManager = flag.Bool("webfm", true, "Enable web file manager for static web server root folder")
8888
enableAutoUpdate = flag.Bool("cfgupgrade", true, "Enable auto config upgrade if breaking change is detected")
8989

90+
/* Default Configuration Flags */
91+
defaultInboundPort = flag.Int("default_inbound_port", 443, "Default web server listening port")
92+
defaultEnableInboundTraffic = flag.Bool("default_inbound_enabled", true, "If web server is enabled by default")
93+
9094
/* Path Configuration Flags */
9195
//path_database = flag.String("dbpath", "./sys.db", "Database path")
9296
//path_conf = flag.String("conf", "./conf", "Configuration folder path")

src/mod/dynamicproxy/Server.go

+16-11
Original file line numberDiff line numberDiff line change
@@ -209,25 +209,18 @@ func (h *ProxyHandler) handleRootRouting(w http.ResponseWriter, r *http.Request)
209209
http.Redirect(w, r, redirectTarget, http.StatusTemporaryRedirect)
210210
case DefaultSite_NotFoundPage:
211211
//Serve the not found page, use template if exists
212-
w.Header().Set("Content-Type", "text/html; charset=utf-8")
213-
w.WriteHeader(http.StatusNotFound)
214-
template, err := os.ReadFile(filepath.Join(h.Parent.Option.WebDirectory, "templates/notfound.html"))
215-
if err != nil {
216-
w.Write(page_hosterror)
217-
} else {
218-
w.Write(template)
219-
}
212+
h.serve404PageWithTemplate(w, r)
220213
case DefaultSite_NoResponse:
221214
//No response. Just close the connection
222-
h.Parent.logRequest(r, false, 444, "root-noresponse", domainOnly)
215+
h.Parent.logRequest(r, false, 444, "root-no_resp", domainOnly)
223216
hijacker, ok := w.(http.Hijacker)
224217
if !ok {
225-
w.Header().Set("Connection", "close")
218+
w.WriteHeader(http.StatusNoContent)
226219
return
227220
}
228221
conn, _, err := hijacker.Hijack()
229222
if err != nil {
230-
w.Header().Set("Connection", "close")
223+
w.WriteHeader(http.StatusNoContent)
231224
return
232225
}
233226
conn.Close()
@@ -241,3 +234,15 @@ func (h *ProxyHandler) handleRootRouting(w http.ResponseWriter, r *http.Request)
241234
http.Error(w, "544 - No Route Defined", 544)
242235
}
243236
}
237+
238+
// Serve 404 page with template if exists
239+
func (h *ProxyHandler) serve404PageWithTemplate(w http.ResponseWriter, r *http.Request) {
240+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
241+
w.WriteHeader(http.StatusNotFound)
242+
template, err := os.ReadFile(filepath.Join(h.Parent.Option.WebDirectory, "templates/notfound.html"))
243+
if err != nil {
244+
w.Write(page_hosterror)
245+
} else {
246+
w.Write(template)
247+
}
248+
}

src/mod/dynamicproxy/domainsniff/proxmox.go

+1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ func IsProxmox(r *http.Request) bool {
1717
return true
1818
}
1919
}
20+
2021
return false
2122
}

src/mod/dynamicproxy/dpcore/dpcore.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dpcore
22

33
import (
44
"context"
5+
"crypto/tls"
56
"errors"
67
"io"
78
"log"
@@ -11,6 +12,7 @@ import (
1112
"strings"
1213
"time"
1314

15+
"golang.org/x/net/http2"
1416
"imuslab.com/zoraxy/mod/dynamicproxy/domainsniff"
1517
"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
1618
)
@@ -84,6 +86,7 @@ type requestCanceler interface {
8486
type DpcoreOptions struct {
8587
IgnoreTLSVerification bool //Disable all TLS verification when request pass through this proxy router
8688
FlushInterval time.Duration //Duration to flush in normal requests. Stream request or keep-alive request will always flush with interval of -1 (immediately)
89+
UseH2CRoundTripper bool //Use H2C RoundTripper for HTTP/2.0 connection
8790
}
8891

8992
func NewDynamicProxyCore(target *url.URL, prepender string, dpcOptions *DpcoreOptions) *ReverseProxy {
@@ -100,8 +103,17 @@ func NewDynamicProxyCore(target *url.URL, prepender string, dpcOptions *DpcoreOp
100103

101104
}
102105

103-
//Hack the default transporter to handle more connections
104106
thisTransporter := http.DefaultTransport
107+
if dpcOptions.UseH2CRoundTripper {
108+
thisTransporter = &http2.Transport{
109+
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
110+
return net.Dial(network, addr)
111+
},
112+
AllowHTTP: true,
113+
}
114+
}
115+
116+
//Hack the default transporter to handle more connections
105117
optimalConcurrentConnection := 32
106118
thisTransporter.(*http.Transport).MaxIdleConns = optimalConcurrentConnection * 2
107119
thisTransporter.(*http.Transport).MaxIdleConnsPerHost = optimalConcurrentConnection

src/mod/dynamicproxy/dynamicproxy.go

+19-2
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,24 @@ func (router *Router) StartProxyService() error {
191191
w.Write([]byte("400 - Bad Request"))
192192
} else {
193193
//No defined sub-domain
194-
http.NotFound(w, r)
194+
if router.Root.DefaultSiteOption == DefaultSite_NoResponse {
195+
//No response. Just close the connection
196+
hijacker, ok := w.(http.Hijacker)
197+
if !ok {
198+
w.Header().Set("Connection", "close")
199+
return
200+
}
201+
conn, _, err := hijacker.Hijack()
202+
if err != nil {
203+
w.Header().Set("Connection", "close")
204+
return
205+
}
206+
conn.Close()
207+
} else {
208+
//Default behavior
209+
http.NotFound(w, r)
210+
}
211+
195212
}
196213

197214
}
@@ -337,7 +354,7 @@ func (router *Router) LoadProxy(matchingDomain string) (*ProxyEndpoint, error) {
337354
return true
338355
}
339356

340-
if key == matchingDomain {
357+
if key == strings.ToLower(matchingDomain) {
341358
targetProxyEndpoint = v
342359
}
343360
return true

src/mod/dynamicproxy/endpoints.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,8 @@ func (ep *ProxyEndpoint) Clone() *ProxyEndpoint {
267267

268268
// Remove this proxy endpoint from running proxy endpoint list
269269
func (ep *ProxyEndpoint) Remove() error {
270-
ep.parent.ProxyEndpoints.Delete(ep.RootOrMatchingDomain)
270+
lookupHostname := strings.ToLower(ep.RootOrMatchingDomain)
271+
ep.parent.ProxyEndpoints.Delete(lookupHostname)
271272
return nil
272273
}
273274

src/mod/dynamicproxy/redirection/redirection.go

+36-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package redirection
22

33
import (
44
"encoding/json"
5-
"fmt"
65
"log"
76
"os"
87
"path"
@@ -111,14 +110,49 @@ func (t *RuleTable) AddRedirectRule(redirectURL string, destURL string, forwardP
111110
return nil
112111
}
113112

113+
// Edit an existing redirection rule, the oldRedirectURL is used to find the rule to be edited
114+
func (t *RuleTable) EditRedirectRule(oldRedirectURL string, newRedirectURL string, destURL string, forwardPathname bool, statusCode int) error {
115+
newRule := &RedirectRules{
116+
RedirectURL: newRedirectURL,
117+
TargetURL: destURL,
118+
ForwardChildpath: forwardPathname,
119+
StatusCode: statusCode,
120+
}
121+
122+
//Remove the old rule
123+
t.DeleteRedirectRule(oldRedirectURL)
124+
125+
// Convert the redirectURL to a valid filename by replacing "/" with "-" and "." with "_"
126+
filename := utils.ReplaceSpecialCharacters(newRedirectURL) + ".json"
127+
filepath := path.Join(t.configPath, filename)
128+
129+
// Create a new file for writing the JSON data
130+
file, err := os.Create(filepath)
131+
if err != nil {
132+
t.log("Error creating file "+filepath, err)
133+
return err
134+
}
135+
defer file.Close()
136+
137+
err = json.NewEncoder(file).Encode(newRule)
138+
if err != nil {
139+
t.log("Error encoding JSON to file "+filepath, err)
140+
return err
141+
}
142+
143+
// Update the runtime map
144+
t.rules.Store(newRedirectURL, newRule)
145+
146+
return nil
147+
}
148+
114149
func (t *RuleTable) DeleteRedirectRule(redirectURL string) error {
115150
// Convert the redirectURL to a valid filename by replacing "/" with "-" and "." with "_"
116151
filename := utils.ReplaceSpecialCharacters(redirectURL) + ".json"
117152

118153
// Create the full file path by joining the t.configPath with the filename
119154
filepath := path.Join(t.configPath, filename)
120155

121-
fmt.Println(redirectURL, filename, filepath)
122156
// Check if the file exists
123157
if _, err := os.Stat(filepath); os.IsNotExist(err) {
124158
return nil // File doesn't exist, nothing to delete

src/mod/dynamicproxy/typedef.go

+1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ type ProxyEndpoint struct {
194194

195195
//Internal Logic Elements
196196
parent *Router `json:"-"`
197+
Tags []string // Tags for the proxy endpoint
197198
}
198199

199200
/*

0 commit comments

Comments
 (0)