mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-08-14 17:09:24 +02:00
Compare commits
20 Commits
v3.2.3
...
2d611a559a
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2d611a559a | ||
![]() |
6c5eba01c2 | ||
![]() |
f641797d10 | ||
![]() |
f92ff068f3 | ||
![]() |
b59ac47c8c | ||
![]() |
8030f3d62a | ||
![]() |
f8f623e3e4 | ||
![]() |
061839756c | ||
![]() |
1dcaa0c257 | ||
![]() |
ffd3909964 | ||
![]() |
3ddccdffce | ||
![]() |
929d4cc82a | ||
![]() |
4f1cd8a571 | ||
![]() |
f6b3656bb1 | ||
![]() |
74a816216e | ||
![]() |
4a093cf096 | ||
![]() |
68f9fccf3a | ||
![]() |
f276040ad0 | ||
![]() |
2f40593daf | ||
![]() |
0b6dbd49bb |
17
.github/workflows/docker.yml
vendored
17
.github/workflows/docker.yml
vendored
@@ -2,7 +2,7 @@ name: Build and push Docker image
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [ published ]
|
types: [ released, prereleased ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup-build-push:
|
setup-build-push:
|
||||||
@@ -33,7 +33,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp -lr $GITHUB_WORKSPACE/src/ $GITHUB_WORKSPACE/docker/src/
|
cp -lr $GITHUB_WORKSPACE/src/ $GITHUB_WORKSPACE/docker/src/
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image (Release)
|
||||||
|
if: "!github.event.release.prerelease"
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: ./docker
|
context: ./docker
|
||||||
@@ -45,3 +46,15 @@ jobs:
|
|||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Build and push Docker image (Prerelease)
|
||||||
|
if: "github.event.release.prerelease"
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: ./docker
|
||||||
|
push: true
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
tags: |
|
||||||
|
zoraxydocker/zoraxy:${{ github.event.release.tag_name }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -56,4 +56,5 @@ log
|
|||||||
tmp
|
tmp
|
||||||
sys.*
|
sys.*
|
||||||
www/html/index.html
|
www/html/index.html
|
||||||
*.exe
|
*.exe
|
||||||
|
/src/dist
|
||||||
|
33
CHANGELOG.md
33
CHANGELOG.md
@@ -1,3 +1,36 @@
|
|||||||
|
# v3.2.4 28 Jun 2025
|
||||||
|
|
||||||
|
A big release since v3.1.9. Versions from 3.2.0 to 3.2.3 were prereleases.
|
||||||
|
|
||||||
|
|
||||||
|
+ Added Authentik support by [JokerQyou](https://github.com/tobychui/zoraxy/commits?author=JokerQyou)
|
||||||
|
+ Added pluginsystem and moved GAN and Zerotier to plugins
|
||||||
|
+ Add loopback detection [#573](https://github.com/tobychui/zoraxy/issues/573)
|
||||||
|
+ Fixed Dark theme not working with Advanced Option accordion [#591](https://github.com/tobychui/zoraxy/issues/591)
|
||||||
|
+ Update logger to include UserAgent by [Raithmir](https://github.com/Raithmir)
|
||||||
|
+ Fixed memory usage in UI [#600](https://github.com/tobychui/zoraxy/issues/600)
|
||||||
|
+ Added docker-compose.yml by [SamuelPalubaCZ](https://github.com/tobychui/zoraxy/commits?author=SamuelPalubaCZ)
|
||||||
|
+ Added more statistics for proxy hosts [#201](https://github.com/tobychui/zoraxy/issues/201) and [#608](https://github.com/tobychui/zoraxy/issues/608)
|
||||||
|
+ Fixed origin field in logs [#618](https://github.com/tobychui/zoraxy/issues/618)
|
||||||
|
+ Added FreeBSD support by Andreas Burri
|
||||||
|
+ Fixed HTTP proxy redirect [#626](https://github.com/tobychui/zoraxy/issues/626)
|
||||||
|
+ Fixed proxy handling #629](https://github.com/tobychui/zoraxy/issues/629)
|
||||||
|
+ Move Scope ID handling into CIDR check by [Nirostar](https://github.com/tobychui/zoraxy/commits?author=Nirostar)
|
||||||
|
+ Prevent the browser from filling the saved Zoraxy login account by [WHFo](https://github.com/tobychui/zoraxy/commits?author=WHFo)
|
||||||
|
+ Added port number and http proto to http proxy list link
|
||||||
|
+ Fixed headers for authelia by [james-d-elliott](https://github.com/tobychui/zoraxy/commits?author=james-d-elliott)
|
||||||
|
+ Refactored docker container list and UI improvements by [eyerrock](https://github.com/tobychui/zoraxy/commits?author=eyerrock)
|
||||||
|
+ Refactored Dockerfile by [PassiveLemon](https://github.com/tobychui/zoraxy/commits?author=PassiveLemon)
|
||||||
|
+ Added new HTTP proxy UI
|
||||||
|
+ Added inbound host name edit function
|
||||||
|
+ Added static web server option to disable listen to all interface
|
||||||
|
+ Merged SSO implementations (Oauth2) [#649](https://github.com/tobychui/zoraxy/pull/649)
|
||||||
|
+ Merged forward-auth optimization [#692(https://github.com/tobychui/zoraxy/pull/692)
|
||||||
|
+ Optimized SSO UI
|
||||||
|
+ Refactored docker image workflows by [PassiveLemon](https://github.com/tobychui/zoraxy/commits?author=PassiveLemon)
|
||||||
|
+ Added disable chunked transfer encoding checkbox (for upstreams that uses legacy HTTP implementations)
|
||||||
|
+ Bug fixes [#694](https://github.com/tobychui/zoraxy/issues/694), [#659](https://github.com/tobychui/zoraxy/issues/659) by [jemmy1794](https://github.com/tobychui/zoraxy/commits?author=jemmy1794), [#695](https://github.com/tobychui/zoraxy/issues/695)
|
||||||
|
|
||||||
# v3.1.9 1 Mar 2025
|
# v3.1.9 1 Mar 2025
|
||||||
|
|
||||||
+ Fixed netstat underflow bug
|
+ Fixed netstat underflow bug
|
||||||
|
@@ -200,6 +200,10 @@ Some section of Zoraxy are contributed by our amazing community and if you have
|
|||||||
|
|
||||||
- Docker Container List by [@eyerrock](https://github.com/eyerrock)
|
- Docker Container List by [@eyerrock](https://github.com/eyerrock)
|
||||||
|
|
||||||
|
- Stream Proxy [@jemmy1794](https://github.com/jemmy1794)
|
||||||
|
|
||||||
|
- Change Log [@Morethanevil](https://github.com/Morethanevil)
|
||||||
|
|
||||||
### Looking for Maintainer
|
### Looking for Maintainer
|
||||||
|
|
||||||
- ACME DNS Challenge Module
|
- ACME DNS Challenge Module
|
||||||
|
@@ -44,7 +44,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
/* Build Constants */
|
/* Build Constants */
|
||||||
SYSTEM_NAME = "Zoraxy"
|
SYSTEM_NAME = "Zoraxy"
|
||||||
SYSTEM_VERSION = "3.2.3"
|
SYSTEM_VERSION = "3.2.4"
|
||||||
DEVELOPMENT_BUILD = false
|
DEVELOPMENT_BUILD = false
|
||||||
|
|
||||||
/* System Constants */
|
/* System Constants */
|
||||||
|
@@ -4,13 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"imuslab.com/zoraxy/mod/database"
|
"imuslab.com/zoraxy/mod/database"
|
||||||
"imuslab.com/zoraxy/mod/info/logger"
|
"imuslab.com/zoraxy/mod/info/logger"
|
||||||
"imuslab.com/zoraxy/mod/utils"
|
"imuslab.com/zoraxy/mod/utils"
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OAuth2RouterOptions struct {
|
type OAuth2RouterOptions struct {
|
||||||
@@ -250,7 +251,19 @@ func (ar *OAuth2Router) HandleOAuth2Auth(w http.ResponseWriter, r *http.Request)
|
|||||||
cookie.SameSite = http.SameSiteLaxMode
|
cookie.SameSite = http.SameSiteLaxMode
|
||||||
}
|
}
|
||||||
w.Header().Add("Set-Cookie", cookie.String())
|
w.Header().Add("Set-Cookie", cookie.String())
|
||||||
http.Redirect(w, r, state, http.StatusTemporaryRedirect)
|
|
||||||
|
//Fix for #695
|
||||||
|
location := strings.TrimPrefix(state, "/internal/")
|
||||||
|
//Check if the location starts with http:// or https://. if yes, this is full URL
|
||||||
|
decodedLocation, err := url.PathUnescape(location)
|
||||||
|
if err == nil && (strings.HasPrefix(decodedLocation, "http://") || strings.HasPrefix(decodedLocation, "https://")) {
|
||||||
|
//Redirect to the full URL
|
||||||
|
http.Redirect(w, r, decodedLocation, http.StatusTemporaryRedirect)
|
||||||
|
} else {
|
||||||
|
//Redirect to a relative path
|
||||||
|
http.Redirect(w, r, state, http.StatusTemporaryRedirect)
|
||||||
|
}
|
||||||
|
|
||||||
return errors.New("authorized")
|
return errors.New("authorized")
|
||||||
}
|
}
|
||||||
unauthorized := false
|
unauthorized := false
|
||||||
|
@@ -330,7 +330,10 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
|
|||||||
locationRewrite := res.Header.Get("Location")
|
locationRewrite := res.Header.Get("Location")
|
||||||
originLocation := res.Header.Get("Location")
|
originLocation := res.Header.Get("Location")
|
||||||
res.Header.Set("zr-origin-location", originLocation)
|
res.Header.Set("zr-origin-location", originLocation)
|
||||||
|
decodedOriginLocation, err := url.PathUnescape(originLocation)
|
||||||
|
if err == nil {
|
||||||
|
originLocation = decodedOriginLocation
|
||||||
|
}
|
||||||
if strings.HasPrefix(originLocation, "http://") || strings.HasPrefix(originLocation, "https://") {
|
if strings.HasPrefix(originLocation, "http://") || strings.HasPrefix(originLocation, "https://") {
|
||||||
//Full path
|
//Full path
|
||||||
//Replace the forwarded target with expected Host
|
//Replace the forwarded target with expected Host
|
||||||
|
@@ -47,15 +47,17 @@ func (m *Manager) HandleAddProxyConfig(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
useTCP, _ := utils.PostBool(r, "useTCP")
|
useTCP, _ := utils.PostBool(r, "useTCP")
|
||||||
useUDP, _ := utils.PostBool(r, "useUDP")
|
useUDP, _ := utils.PostBool(r, "useUDP")
|
||||||
|
useProxyProtocol, _ := utils.PostBool(r, "useProxyProtocol")
|
||||||
|
|
||||||
//Create the target config
|
//Create the target config
|
||||||
newConfigUUID := m.NewConfig(&ProxyRelayOptions{
|
newConfigUUID := m.NewConfig(&ProxyRelayOptions{
|
||||||
Name: name,
|
Name: name,
|
||||||
ListeningAddr: strings.TrimSpace(listenAddr),
|
ListeningAddr: strings.TrimSpace(listenAddr),
|
||||||
ProxyAddr: strings.TrimSpace(proxyAddr),
|
ProxyAddr: strings.TrimSpace(proxyAddr),
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
UseTCP: useTCP,
|
UseTCP: useTCP,
|
||||||
UseUDP: useUDP,
|
UseUDP: useUDP,
|
||||||
|
UseProxyProtocol: useProxyProtocol,
|
||||||
})
|
})
|
||||||
|
|
||||||
js, _ := json.Marshal(newConfigUUID)
|
js, _ := json.Marshal(newConfigUUID)
|
||||||
@@ -75,6 +77,7 @@ func (m *Manager) HandleEditProxyConfigs(w http.ResponseWriter, r *http.Request)
|
|||||||
proxyAddr, _ := utils.PostPara(r, "proxyAddr")
|
proxyAddr, _ := utils.PostPara(r, "proxyAddr")
|
||||||
useTCP, _ := utils.PostBool(r, "useTCP")
|
useTCP, _ := utils.PostBool(r, "useTCP")
|
||||||
useUDP, _ := utils.PostBool(r, "useUDP")
|
useUDP, _ := utils.PostBool(r, "useUDP")
|
||||||
|
useProxyProtocol, _ := utils.PostBool(r, "useProxyProtocol")
|
||||||
|
|
||||||
newTimeoutStr, _ := utils.PostPara(r, "timeout")
|
newTimeoutStr, _ := utils.PostPara(r, "timeout")
|
||||||
newTimeout := -1
|
newTimeout := -1
|
||||||
@@ -86,8 +89,20 @@ func (m *Manager) HandleEditProxyConfigs(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new ProxyRuleUpdateConfig with the extracted parameters
|
||||||
|
newConfig := &ProxyRuleUpdateConfig{
|
||||||
|
InstanceUUID: configUUID,
|
||||||
|
NewName: newName,
|
||||||
|
NewListeningAddr: listenAddr,
|
||||||
|
NewProxyAddr: proxyAddr,
|
||||||
|
UseTCP: useTCP,
|
||||||
|
UseUDP: useUDP,
|
||||||
|
UseProxyProtocol: useProxyProtocol,
|
||||||
|
NewTimeout: newTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
// Call the EditConfig method to modify the configuration
|
// Call the EditConfig method to modify the configuration
|
||||||
err = m.EditConfig(configUUID, newName, listenAddr, proxyAddr, useTCP, useUDP, newTimeout)
|
err = m.EditConfig(newConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.SendErrorResponse(w, err.Error())
|
utils.SendErrorResponse(w, err.Error())
|
||||||
return
|
return
|
||||||
|
97
src/mod/streamproxy/instances.go
Normal file
97
src/mod/streamproxy/instances.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package streamproxy
|
||||||
|
|
||||||
|
/*
|
||||||
|
Instances.go
|
||||||
|
|
||||||
|
This file contains the methods to start, stop, and manage the proxy relay instances.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Start a proxy if stopped
|
||||||
|
func (c *ProxyRelayInstance) Start() error {
|
||||||
|
if c.IsRunning() {
|
||||||
|
c.Running = true
|
||||||
|
return errors.New("proxy already running")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a stopChan to control the loop
|
||||||
|
tcpStopChan := make(chan bool)
|
||||||
|
udpStopChan := make(chan bool)
|
||||||
|
|
||||||
|
//Start the proxy service
|
||||||
|
if c.UseUDP {
|
||||||
|
c.udpStopChan = udpStopChan
|
||||||
|
go func() {
|
||||||
|
err := c.ForwardUDP(c.ListeningAddress, c.ProxyTargetAddr, udpStopChan)
|
||||||
|
if err != nil {
|
||||||
|
if !c.UseTCP {
|
||||||
|
c.Running = false
|
||||||
|
c.udpStopChan = nil
|
||||||
|
c.parent.SaveConfigToDatabase()
|
||||||
|
}
|
||||||
|
c.parent.logf("[proto:udp] Error starting stream proxy "+c.Name+"("+c.UUID+")", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.UseTCP {
|
||||||
|
c.tcpStopChan = tcpStopChan
|
||||||
|
go func() {
|
||||||
|
//Default to transport mode
|
||||||
|
err := c.Port2host(c.ListeningAddress, c.ProxyTargetAddr, tcpStopChan)
|
||||||
|
if err != nil {
|
||||||
|
c.Running = false
|
||||||
|
c.tcpStopChan = nil
|
||||||
|
c.parent.SaveConfigToDatabase()
|
||||||
|
c.parent.logf("[proto:tcp] Error starting stream proxy "+c.Name+"("+c.UUID+")", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
//Successfully spawned off the proxy routine
|
||||||
|
c.Running = true
|
||||||
|
c.parent.SaveConfigToDatabase()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if a proxy config is running
|
||||||
|
func (c *ProxyRelayInstance) IsRunning() bool {
|
||||||
|
return c.tcpStopChan != nil || c.udpStopChan != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart a proxy config
|
||||||
|
func (c *ProxyRelayInstance) Restart() {
|
||||||
|
if c.IsRunning() {
|
||||||
|
c.Stop()
|
||||||
|
}
|
||||||
|
time.Sleep(3000 * time.Millisecond)
|
||||||
|
c.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop a running proxy if running
|
||||||
|
func (c *ProxyRelayInstance) Stop() {
|
||||||
|
c.parent.logf("Stopping Stream Proxy "+c.Name, nil)
|
||||||
|
|
||||||
|
if c.udpStopChan != nil {
|
||||||
|
c.parent.logf("Stopping UDP for "+c.Name, nil)
|
||||||
|
c.udpStopChan <- true
|
||||||
|
c.udpStopChan = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.tcpStopChan != nil {
|
||||||
|
c.parent.logf("Stopping TCP for "+c.Name, nil)
|
||||||
|
c.tcpStopChan <- true
|
||||||
|
c.tcpStopChan = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
c.parent.logf("Stopped Stream Proxy "+c.Name, nil)
|
||||||
|
c.Running = false
|
||||||
|
|
||||||
|
//Update the running status
|
||||||
|
c.parent.SaveConfigToDatabase()
|
||||||
|
}
|
@@ -8,7 +8,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"imuslab.com/zoraxy/mod/info/logger"
|
"imuslab.com/zoraxy/mod/info/logger"
|
||||||
@@ -24,24 +23,41 @@ import (
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
type ProxyRelayOptions struct {
|
type ProxyRelayOptions struct {
|
||||||
Name string
|
Name string
|
||||||
ListeningAddr string
|
ListeningAddr string
|
||||||
ProxyAddr string
|
ProxyAddr string
|
||||||
Timeout int
|
Timeout int
|
||||||
UseTCP bool
|
UseTCP bool
|
||||||
UseUDP bool
|
UseUDP bool
|
||||||
|
UseProxyProtocol bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProxyRelayConfig struct {
|
// ProxyRuleUpdateConfig is used to update the proxy rule config
|
||||||
UUID string //A UUIDv4 representing this config
|
type ProxyRuleUpdateConfig struct {
|
||||||
Name string //Name of the config
|
InstanceUUID string //The target instance UUID to update
|
||||||
Running bool //Status, read only
|
NewName string //New name for the instance, leave empty for no change
|
||||||
AutoStart bool //If the service suppose to started automatically
|
NewListeningAddr string //New listening address, leave empty for no change
|
||||||
ListeningAddress string //Listening Address, usually 127.0.0.1:port
|
NewProxyAddr string //New proxy target address, leave empty for no change
|
||||||
ProxyTargetAddr string //Proxy target address
|
UseTCP bool //Enable TCP proxy, default to false
|
||||||
UseTCP bool //Enable TCP proxy
|
UseUDP bool //Enable UDP proxy, default to false
|
||||||
UseUDP bool //Enable UDP proxy
|
UseProxyProtocol bool //Enable Proxy Protocol, default to false
|
||||||
Timeout int //Timeout for connection in sec
|
NewTimeout int //New timeout for the connection, leave -1 for no change
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProxyRelayInstance struct {
|
||||||
|
/* Runtime Config */
|
||||||
|
UUID string //A UUIDv4 representing this config
|
||||||
|
Name string //Name of the config
|
||||||
|
Running bool //Status, read only
|
||||||
|
AutoStart bool //If the service suppose to started automatically
|
||||||
|
ListeningAddress string //Listening Address, usually 127.0.0.1:port
|
||||||
|
ProxyTargetAddr string //Proxy target address
|
||||||
|
UseTCP bool //Enable TCP proxy
|
||||||
|
UseUDP bool //Enable UDP proxy
|
||||||
|
UseProxyProtocol bool //Enable Proxy Protocol
|
||||||
|
Timeout int //Timeout for connection in sec
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
tcpStopChan chan bool //Stop channel for TCP listener
|
tcpStopChan chan bool //Stop channel for TCP listener
|
||||||
udpStopChan chan bool //Stop channel for UDP listener
|
udpStopChan chan bool //Stop channel for UDP listener
|
||||||
aTobAccumulatedByteTransfer atomic.Int64 //Accumulated byte transfer from A to B
|
aTobAccumulatedByteTransfer atomic.Int64 //Accumulated byte transfer from A to B
|
||||||
@@ -60,13 +76,14 @@ type Options struct {
|
|||||||
type Manager struct {
|
type Manager struct {
|
||||||
//Config and stores
|
//Config and stores
|
||||||
Options *Options
|
Options *Options
|
||||||
Configs []*ProxyRelayConfig
|
Configs []*ProxyRelayInstance
|
||||||
|
|
||||||
//Realtime Statistics
|
//Realtime Statistics
|
||||||
Connections int //currently connected connect counts
|
Connections int //currently connected connect counts
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewStreamProxy creates a new stream proxy manager with the given options
|
||||||
func NewStreamProxy(options *Options) (*Manager, error) {
|
func NewStreamProxy(options *Options) (*Manager, error) {
|
||||||
if !utils.FileExists(options.ConfigStore) {
|
if !utils.FileExists(options.ConfigStore) {
|
||||||
err := os.MkdirAll(options.ConfigStore, 0775)
|
err := os.MkdirAll(options.ConfigStore, 0775)
|
||||||
@@ -76,7 +93,7 @@ func NewStreamProxy(options *Options) (*Manager, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Load relay configs from db
|
//Load relay configs from db
|
||||||
previousRules := []*ProxyRelayConfig{}
|
previousRules := []*ProxyRelayInstance{}
|
||||||
streamProxyConfigFiles, err := filepath.Glob(options.ConfigStore + "/*.config")
|
streamProxyConfigFiles, err := filepath.Glob(options.ConfigStore + "/*.config")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -89,7 +106,7 @@ func NewStreamProxy(options *Options) (*Manager, error) {
|
|||||||
options.Logger.PrintAndLog("stream-prox", "Read stream proxy config failed", err)
|
options.Logger.PrintAndLog("stream-prox", "Read stream proxy config failed", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
thisRelayConfig := &ProxyRelayConfig{}
|
thisRelayConfig := &ProxyRelayInstance{}
|
||||||
err = json.Unmarshal(configBytes, thisRelayConfig)
|
err = json.Unmarshal(configBytes, thisRelayConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
options.Logger.PrintAndLog("stream-prox", "Unmarshal stream proxy config failed", err)
|
options.Logger.PrintAndLog("stream-prox", "Unmarshal stream proxy config failed", err)
|
||||||
@@ -142,6 +159,7 @@ func (m *Manager) logf(message string, originalError error) {
|
|||||||
m.Options.Logger.PrintAndLog("stream-prox", message, originalError)
|
m.Options.Logger.PrintAndLog("stream-prox", message, originalError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewConfig creates a new proxy relay config with the given options
|
||||||
func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
|
func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
|
||||||
//Generate two zero value for atomic int64
|
//Generate two zero value for atomic int64
|
||||||
aAcc := atomic.Int64{}
|
aAcc := atomic.Int64{}
|
||||||
@@ -150,13 +168,14 @@ func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
|
|||||||
bAcc.Store(0)
|
bAcc.Store(0)
|
||||||
//Generate a new config from options
|
//Generate a new config from options
|
||||||
configUUID := uuid.New().String()
|
configUUID := uuid.New().String()
|
||||||
thisConfig := ProxyRelayConfig{
|
thisConfig := ProxyRelayInstance{
|
||||||
UUID: configUUID,
|
UUID: configUUID,
|
||||||
Name: config.Name,
|
Name: config.Name,
|
||||||
ListeningAddress: config.ListeningAddr,
|
ListeningAddress: config.ListeningAddr,
|
||||||
ProxyTargetAddr: config.ProxyAddr,
|
ProxyTargetAddr: config.ProxyAddr,
|
||||||
UseTCP: config.UseTCP,
|
UseTCP: config.UseTCP,
|
||||||
UseUDP: config.UseUDP,
|
UseUDP: config.UseUDP,
|
||||||
|
UseProxyProtocol: config.UseProxyProtocol,
|
||||||
Timeout: config.Timeout,
|
Timeout: config.Timeout,
|
||||||
tcpStopChan: nil,
|
tcpStopChan: nil,
|
||||||
udpStopChan: nil,
|
udpStopChan: nil,
|
||||||
@@ -170,7 +189,7 @@ func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
|
|||||||
return configUUID
|
return configUUID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) GetConfigByUUID(configUUID string) (*ProxyRelayConfig, error) {
|
func (m *Manager) GetConfigByUUID(configUUID string) (*ProxyRelayInstance, error) {
|
||||||
// Find and return the config with the specified UUID
|
// Find and return the config with the specified UUID
|
||||||
for _, config := range m.Configs {
|
for _, config := range m.Configs {
|
||||||
if config.UUID == configUUID {
|
if config.UUID == configUUID {
|
||||||
@@ -181,32 +200,33 @@ func (m *Manager) GetConfigByUUID(configUUID string) (*ProxyRelayConfig, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Edit the config based on config UUID, leave empty for unchange fields
|
// Edit the config based on config UUID, leave empty for unchange fields
|
||||||
func (m *Manager) EditConfig(configUUID string, newName string, newListeningAddr string, newProxyAddr string, useTCP bool, useUDP bool, newTimeout int) error {
|
func (m *Manager) EditConfig(newConfig *ProxyRuleUpdateConfig) error {
|
||||||
// Find the config with the specified UUID
|
// Find the config with the specified UUID
|
||||||
foundConfig, err := m.GetConfigByUUID(configUUID)
|
foundConfig, err := m.GetConfigByUUID(newConfig.InstanceUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate and update the fields
|
// Validate and update the fields
|
||||||
if newName != "" {
|
if newConfig.NewName != "" {
|
||||||
foundConfig.Name = newName
|
foundConfig.Name = newConfig.NewName
|
||||||
}
|
}
|
||||||
if newListeningAddr != "" {
|
if newConfig.NewListeningAddr != "" {
|
||||||
foundConfig.ListeningAddress = newListeningAddr
|
foundConfig.ListeningAddress = newConfig.NewListeningAddr
|
||||||
}
|
}
|
||||||
if newProxyAddr != "" {
|
if newConfig.NewProxyAddr != "" {
|
||||||
foundConfig.ProxyTargetAddr = newProxyAddr
|
foundConfig.ProxyTargetAddr = newConfig.NewProxyAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
foundConfig.UseTCP = useTCP
|
foundConfig.UseTCP = newConfig.UseTCP
|
||||||
foundConfig.UseUDP = useUDP
|
foundConfig.UseUDP = newConfig.UseUDP
|
||||||
|
foundConfig.UseProxyProtocol = newConfig.UseProxyProtocol
|
||||||
|
|
||||||
if newTimeout != -1 {
|
if newConfig.NewTimeout != -1 {
|
||||||
if newTimeout < 0 {
|
if newConfig.NewTimeout < 0 {
|
||||||
return errors.New("invalid timeout value given")
|
return errors.New("invalid timeout value given")
|
||||||
}
|
}
|
||||||
foundConfig.Timeout = newTimeout
|
foundConfig.Timeout = newConfig.NewTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
m.SaveConfigToDatabase()
|
m.SaveConfigToDatabase()
|
||||||
@@ -215,12 +235,11 @@ func (m *Manager) EditConfig(configUUID string, newName string, newListeningAddr
|
|||||||
if foundConfig.IsRunning() {
|
if foundConfig.IsRunning() {
|
||||||
foundConfig.Restart()
|
foundConfig.Restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the config from file by UUID
|
||||||
func (m *Manager) RemoveConfig(configUUID string) error {
|
func (m *Manager) RemoveConfig(configUUID string) error {
|
||||||
//Remove the config from file
|
|
||||||
err := os.Remove(filepath.Join(m.Options.ConfigStore, configUUID+".config"))
|
err := os.Remove(filepath.Join(m.Options.ConfigStore, configUUID+".config"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -250,91 +269,3 @@ func (m *Manager) SaveConfigToDatabase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Config Functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Start a proxy if stopped
|
|
||||||
func (c *ProxyRelayConfig) Start() error {
|
|
||||||
if c.IsRunning() {
|
|
||||||
c.Running = true
|
|
||||||
return errors.New("proxy already running")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a stopChan to control the loop
|
|
||||||
tcpStopChan := make(chan bool)
|
|
||||||
udpStopChan := make(chan bool)
|
|
||||||
|
|
||||||
//Start the proxy service
|
|
||||||
if c.UseUDP {
|
|
||||||
c.udpStopChan = udpStopChan
|
|
||||||
go func() {
|
|
||||||
err := c.ForwardUDP(c.ListeningAddress, c.ProxyTargetAddr, udpStopChan)
|
|
||||||
if err != nil {
|
|
||||||
if !c.UseTCP {
|
|
||||||
c.Running = false
|
|
||||||
c.udpStopChan = nil
|
|
||||||
c.parent.SaveConfigToDatabase()
|
|
||||||
}
|
|
||||||
c.parent.logf("[proto:udp] Error starting stream proxy "+c.Name+"("+c.UUID+")", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.UseTCP {
|
|
||||||
c.tcpStopChan = tcpStopChan
|
|
||||||
go func() {
|
|
||||||
//Default to transport mode
|
|
||||||
err := c.Port2host(c.ListeningAddress, c.ProxyTargetAddr, tcpStopChan)
|
|
||||||
if err != nil {
|
|
||||||
c.Running = false
|
|
||||||
c.tcpStopChan = nil
|
|
||||||
c.parent.SaveConfigToDatabase()
|
|
||||||
c.parent.logf("[proto:tcp] Error starting stream proxy "+c.Name+"("+c.UUID+")", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
//Successfully spawned off the proxy routine
|
|
||||||
c.Running = true
|
|
||||||
c.parent.SaveConfigToDatabase()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return if a proxy config is running
|
|
||||||
func (c *ProxyRelayConfig) IsRunning() bool {
|
|
||||||
return c.tcpStopChan != nil || c.udpStopChan != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restart a proxy config
|
|
||||||
func (c *ProxyRelayConfig) Restart() {
|
|
||||||
if c.IsRunning() {
|
|
||||||
c.Stop()
|
|
||||||
}
|
|
||||||
time.Sleep(3000 * time.Millisecond)
|
|
||||||
c.Start()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop a running proxy if running
|
|
||||||
func (c *ProxyRelayConfig) Stop() {
|
|
||||||
c.parent.logf("Stopping Stream Proxy "+c.Name, nil)
|
|
||||||
|
|
||||||
if c.udpStopChan != nil {
|
|
||||||
c.parent.logf("Stopping UDP for "+c.Name, nil)
|
|
||||||
c.udpStopChan <- true
|
|
||||||
c.udpStopChan = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.tcpStopChan != nil {
|
|
||||||
c.parent.logf("Stopping TCP for "+c.Name, nil)
|
|
||||||
c.tcpStopChan <- true
|
|
||||||
c.tcpStopChan = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
c.parent.logf("Stopped Stream Proxy "+c.Name, nil)
|
|
||||||
c.Running = false
|
|
||||||
|
|
||||||
//Update the running status
|
|
||||||
c.parent.SaveConfigToDatabase()
|
|
||||||
}
|
|
||||||
|
@@ -12,7 +12,7 @@ func TestPort2Port(t *testing.T) {
|
|||||||
stopChan := make(chan bool)
|
stopChan := make(chan bool)
|
||||||
|
|
||||||
// Create a ProxyRelayConfig with dummy values
|
// Create a ProxyRelayConfig with dummy values
|
||||||
config := &streamproxy.ProxyRelayConfig{
|
config := &streamproxy.ProxyRelayInstance{
|
||||||
Timeout: 1,
|
Timeout: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@ package streamproxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@@ -43,6 +44,23 @@ func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup, accumulator *a
|
|||||||
wg.Done()
|
wg.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeProxyProtocolHeaderV1(dst net.Conn, src net.Conn) error {
|
||||||
|
clientAddr, ok1 := src.RemoteAddr().(*net.TCPAddr)
|
||||||
|
proxyAddr, ok2 := src.LocalAddr().(*net.TCPAddr)
|
||||||
|
if !ok1 || !ok2 {
|
||||||
|
return errors.New("invalid TCP address for proxy protocol")
|
||||||
|
}
|
||||||
|
|
||||||
|
header := fmt.Sprintf("PROXY TCP4 %s %s %d %d\r\n",
|
||||||
|
clientAddr.IP.String(),
|
||||||
|
proxyAddr.IP.String(),
|
||||||
|
clientAddr.Port,
|
||||||
|
proxyAddr.Port)
|
||||||
|
|
||||||
|
_, err := dst.Write([]byte(header))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func forward(conn1 net.Conn, conn2 net.Conn, aTob *atomic.Int64, bToa *atomic.Int64) {
|
func forward(conn1 net.Conn, conn2 net.Conn, aTob *atomic.Int64, bToa *atomic.Int64) {
|
||||||
log.Printf("[+] start transmit. [%s],[%s] <-> [%s],[%s] \n", conn1.LocalAddr().String(), conn1.RemoteAddr().String(), conn2.LocalAddr().String(), conn2.RemoteAddr().String())
|
log.Printf("[+] start transmit. [%s],[%s] <-> [%s],[%s] \n", conn1.LocalAddr().String(), conn1.RemoteAddr().String(), conn2.LocalAddr().String(), conn2.RemoteAddr().String())
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
@@ -54,7 +72,7 @@ func forward(conn1 net.Conn, conn2 net.Conn, aTob *atomic.Int64, bToa *atomic.In
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ProxyRelayConfig) accept(listener net.Listener) (net.Conn, error) {
|
func (c *ProxyRelayInstance) accept(listener net.Listener) (net.Conn, error) {
|
||||||
conn, err := listener.Accept()
|
conn, err := listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -92,7 +110,7 @@ func startListener(address string) (net.Listener, error) {
|
|||||||
portA -> server
|
portA -> server
|
||||||
server -> portB
|
server -> portB
|
||||||
*/
|
*/
|
||||||
func (c *ProxyRelayConfig) Port2host(allowPort string, targetAddress string, stopChan chan bool) error {
|
func (c *ProxyRelayInstance) Port2host(allowPort string, targetAddress string, stopChan chan bool) error {
|
||||||
listenerStartingAddr := allowPort
|
listenerStartingAddr := allowPort
|
||||||
if isValidPort(allowPort) {
|
if isValidPort(allowPort) {
|
||||||
//number only, e.g. 8080
|
//number only, e.g. 8080
|
||||||
@@ -140,6 +158,20 @@ func (c *ProxyRelayConfig) Port2host(allowPort string, targetAddress string, sto
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Println("[→]", "connect target address ["+targetAddress+"] success.")
|
log.Println("[→]", "connect target address ["+targetAddress+"] success.")
|
||||||
|
|
||||||
|
if c.UseProxyProtocol {
|
||||||
|
log.Println("[+]", "write proxy protocol header to target address ["+targetAddress+"]")
|
||||||
|
err = writeProxyProtocolHeaderV1(target, conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[x]", "Write proxy protocol header faild: ", err)
|
||||||
|
target.Close()
|
||||||
|
conn.Close()
|
||||||
|
log.Println("[←]", "close the connect at local:["+conn.LocalAddr().String()+"] and remote:["+conn.RemoteAddr().String()+"]")
|
||||||
|
time.Sleep(time.Duration(c.Timeout) * time.Second)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
forward(target, conn, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer)
|
forward(target, conn, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer)
|
||||||
}(targetAddress)
|
}(targetAddress)
|
||||||
}
|
}
|
||||||
|
@@ -53,7 +53,7 @@ func initUDPConnections(listenAddr string, targetAddress string) (*net.UDPConn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Go routine which manages connection from server to single client
|
// Go routine which manages connection from server to single client
|
||||||
func (c *ProxyRelayConfig) RunUDPConnectionRelay(conn *udpClientServerConn, lisenter *net.UDPConn) {
|
func (c *ProxyRelayInstance) RunUDPConnectionRelay(conn *udpClientServerConn, lisenter *net.UDPConn) {
|
||||||
var buffer [1500]byte
|
var buffer [1500]byte
|
||||||
for {
|
for {
|
||||||
// Read from server
|
// Read from server
|
||||||
@@ -74,7 +74,7 @@ func (c *ProxyRelayConfig) RunUDPConnectionRelay(conn *udpClientServerConn, lise
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close all connections that waiting for read from server
|
// Close all connections that waiting for read from server
|
||||||
func (c *ProxyRelayConfig) CloseAllUDPConnections() {
|
func (c *ProxyRelayInstance) CloseAllUDPConnections() {
|
||||||
c.udpClientMap.Range(func(clientAddr, clientServerConn interface{}) bool {
|
c.udpClientMap.Range(func(clientAddr, clientServerConn interface{}) bool {
|
||||||
conn := clientServerConn.(*udpClientServerConn)
|
conn := clientServerConn.(*udpClientServerConn)
|
||||||
conn.ServerConn.Close()
|
conn.ServerConn.Close()
|
||||||
@@ -82,7 +82,7 @@ func (c *ProxyRelayConfig) CloseAllUDPConnections() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ProxyRelayConfig) ForwardUDP(address1, address2 string, stopChan chan bool) error {
|
func (c *ProxyRelayInstance) ForwardUDP(address1, address2 string, stopChan chan bool) error {
|
||||||
//By default the incoming listen Address is int
|
//By default the incoming listen Address is int
|
||||||
//We need to add the loopback address into it
|
//We need to add the loopback address into it
|
||||||
if isValidPort(address1) {
|
if isValidPort(address1) {
|
||||||
@@ -90,8 +90,8 @@ func (c *ProxyRelayConfig) ForwardUDP(address1, address2 string, stopChan chan b
|
|||||||
address1 = ":" + address1
|
address1 = ":" + address1
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(address1, ":") {
|
if strings.HasPrefix(address1, ":") {
|
||||||
//Prepend 127.0.0.1 to the address
|
//Prepend 0.0.0.0 to the address
|
||||||
address1 = "127.0.0.1" + address1
|
address1 = "0.0.0.0" + address1
|
||||||
}
|
}
|
||||||
|
|
||||||
lisener, targetAddr, err := initUDPConnections(address1, address2)
|
lisener, targetAddr, err := initUDPConnections(address1, address2)
|
||||||
|
@@ -69,6 +69,12 @@ func (ws *WebServer) HandlePortChange(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if newPort is a valid TCP port number (1-65535)
|
||||||
|
if newPort < 1 || newPort > 65535 {
|
||||||
|
utils.SendErrorResponse(w, "invalid port number given")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = ws.ChangePort(strconv.Itoa(newPort))
|
err = ws.ChangePort(strconv.Itoa(newPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.SendErrorResponse(w, err.Error())
|
utils.SendErrorResponse(w, err.Error())
|
||||||
@@ -106,6 +112,17 @@ func (ws *WebServer) SetDisableListenToAllInterface(w http.ResponseWriter, r *ht
|
|||||||
utils.SendErrorResponse(w, "unable to save setting")
|
utils.SendErrorResponse(w, "unable to save setting")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the option in the web server instance
|
||||||
ws.option.DisableListenToAllInterface = disableListen
|
ws.option.DisableListenToAllInterface = disableListen
|
||||||
|
|
||||||
|
// If the server is running and the setting is changed, we need to restart the server
|
||||||
|
if ws.IsRunning() {
|
||||||
|
err = ws.Restart()
|
||||||
|
if err != nil {
|
||||||
|
utils.SendErrorResponse(w, "unable to restart web server: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
utils.SendOK(w)
|
utils.SendOK(w)
|
||||||
}
|
}
|
||||||
|
@@ -210,6 +210,27 @@ func (ws *WebServer) Stop() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ws *WebServer) Restart() error {
|
||||||
|
if ws.isRunning {
|
||||||
|
if err := ws.Stop(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ws.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.option.Logger.PrintAndLog("static-webserv", "Static Web Server restarted. Listening on :"+ws.option.Port, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *WebServer) IsRunning() bool {
|
||||||
|
ws.mu.Lock()
|
||||||
|
defer ws.mu.Unlock()
|
||||||
|
return ws.isRunning
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateDirectoryListing enables or disables directory listing.
|
// UpdateDirectoryListing enables or disables directory listing.
|
||||||
func (ws *WebServer) UpdateDirectoryListing(enable bool) {
|
func (ws *WebServer) UpdateDirectoryListing(enable bool) {
|
||||||
ws.option.EnableDirectoryListing = enable
|
ws.option.EnableDirectoryListing = enable
|
||||||
|
@@ -203,7 +203,7 @@
|
|||||||
<th>Destination</th>
|
<th>Destination</th>
|
||||||
<th>Virtual Directory</th>
|
<th>Virtual Directory</th>
|
||||||
<th class="no-sort">Tags</th>
|
<th class="no-sort">Tags</th>
|
||||||
<th class="no-sort" style="width:50px; cursor: default !important;"></th>
|
<th class="no-sort" style="width:100px; cursor: default !important;"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="httpProxyList">
|
<tbody id="httpProxyList">
|
||||||
@@ -588,7 +588,7 @@
|
|||||||
</td> -->
|
</td> -->
|
||||||
<td class="center aligned ignoremw" editable="true" datatype="action" data-label="">
|
<td class="center aligned ignoremw" editable="true" datatype="action" data-label="">
|
||||||
<button title="Edit Proxy Rule" class="ui circular small basic icon button editBtn inlineEditActionBtn" onclick='editEndpoint("${(subd.RootOrMatchingDomain).hexEncode()}")'><i class="ellipsis vertical icon"></i></button>
|
<button title="Edit Proxy Rule" class="ui circular small basic icon button editBtn inlineEditActionBtn" onclick='editEndpoint("${(subd.RootOrMatchingDomain).hexEncode()}")'><i class="ellipsis vertical icon"></i></button>
|
||||||
<!-- <button title="Remove Proxy Rule" class="ui circular mini red basic icon button inlineEditActionBtn" onclick='deleteEndpoint("${(subd.RootOrMatchingDomain).hexEncode()}")'><i class="trash icon"></i></button> -->
|
<button title="Remove Proxy Rule" class="ui circular mini red basic icon button inlineEditActionBtn" onclick='deleteEndpoint("${(subd.RootOrMatchingDomain).hexEncode()}")'><i class="trash icon"></i></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>`);
|
</tr>`);
|
||||||
});
|
});
|
||||||
|
@@ -3,18 +3,15 @@
|
|||||||
<h2>SSO</h2>
|
<h2>SSO</h2>
|
||||||
<p>Single Sign-On (SSO) and authentication providers settings </p>
|
<p>Single Sign-On (SSO) and authentication providers settings </p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui basic segment">
|
|
||||||
<div class="ui yellow message">
|
|
||||||
<div class="header">
|
|
||||||
Experimental Feature
|
|
||||||
</div>
|
|
||||||
<p>Please note that this feature is still in development and may not work as expected.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div class="ui basic segment">
|
<div class="ui top attached tabular menu ssoTabs">
|
||||||
<h3>Forward Auth</h3>
|
<a class="item active" data-tab="forward_auth_tab">Forward Auth</a>
|
||||||
|
<a class="item" data-tab="oauth2_tab">Oauth2</a>
|
||||||
|
<!-- <a class="item" data-tab="zoraxy_sso_tab">Zoraxy SSO</a> -->
|
||||||
|
</div>
|
||||||
|
<div class="ui bottom attached tab segment active" data-tab="forward_auth_tab">
|
||||||
|
<!-- Forward Auth -->
|
||||||
|
<h2>Forward Auth</h2>
|
||||||
<p>Configuration settings for the Forward Auth provider.</p>
|
<p>Configuration settings for the Forward Auth provider.</p>
|
||||||
<p>The Forward Auth provider makes a subrequest to an authorization server that supports Forward Auth, then either:</p>
|
<p>The Forward Auth provider makes a subrequest to an authorization server that supports Forward Auth, then either:</p>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -86,10 +83,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<button class="ui basic button" type="submit"><i class="green check icon"></i> Apply Change</button>
|
<button class="ui basic button" type="submit"><i class="green check icon"></i> Apply Change</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui bottom attached tab segment" data-tab="oauth2_tab">
|
||||||
<div class="ui basic segment">
|
<!-- Oauth 2 -->
|
||||||
<h3>OAuth 2.0</h3>
|
<h2>OAuth 2.0</h2>
|
||||||
<p>Configuration settings for OAuth 2.0 authentication provider.</p>
|
<p>Configuration settings for OAuth 2.0 authentication provider.</p>
|
||||||
|
|
||||||
<form class="ui form" action="#" id="oauth2Settings">
|
<form class="ui form" action="#" id="oauth2Settings">
|
||||||
@@ -134,11 +131,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<button class="ui basic button" type="submit"><i class="green check icon"></i> Apply Change</button>
|
<button class="ui basic button" type="submit"><i class="green check icon"></i> Apply Change</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui bottom attached tab segment" data-tab="zoraxy_sso_tab">
|
||||||
|
<!-- Zoraxy SSO -->
|
||||||
|
<h3>Zoraxy SSO</h3>
|
||||||
|
<p>Configuration settings for Zoraxy SSO provider.</p>
|
||||||
|
<p>Currently not implemented.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
$(".ssoTabs .item").tab();
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
/* Load forward-auth settings from backend */
|
/* Load forward-auth settings from backend */
|
||||||
$.cjax({
|
$.cjax({
|
||||||
|
@@ -73,6 +73,14 @@
|
|||||||
<small>Forward UDP request on this listening socket</small></label>
|
<small>Forward UDP request on this listening socket</small></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui toggle checkbox">
|
||||||
|
<input type="checkbox" tabindex="0" name="useProxyProtocol" class="hidden">
|
||||||
|
<label>Enable Proxy Protocol V1<br>
|
||||||
|
<small>Enable TCP Proxy Protocol header V1</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<button id="addStreamProxyButton" class="ui basic button" type="submit"><i class="ui green add icon"></i> Create</button>
|
<button id="addStreamProxyButton" class="ui basic button" type="submit"><i class="ui green add icon"></i> Create</button>
|
||||||
<button id="editStreamProxyButton" class="ui basic button" onclick="confirmEditTCPProxyConfig(event, this);" style="display:none;"><i class="ui green check icon"></i> Update</button>
|
<button id="editStreamProxyButton" class="ui basic button" onclick="confirmEditTCPProxyConfig(event, this);" style="display:none;"><i class="ui green check icon"></i> Update</button>
|
||||||
<button class="ui basic red button" onclick="event.preventDefault(); cancelStreamProxyEdit(event);"><i class="ui red remove icon"></i> Cancel</button>
|
<button class="ui basic red button" onclick="event.preventDefault(); cancelStreamProxyEdit(event);"><i class="ui red remove icon"></i> Cancel</button>
|
||||||
@@ -195,6 +203,10 @@
|
|||||||
modeText.push("UDP")
|
modeText.push("UDP")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.UseProxyProtocol){
|
||||||
|
modeText.push("ProxyProtocol V1")
|
||||||
|
}
|
||||||
|
|
||||||
modeText = modeText.join(" & ")
|
modeText = modeText.join(" & ")
|
||||||
|
|
||||||
var thisConfig = encodeURIComponent(JSON.stringify(config));
|
var thisConfig = encodeURIComponent(JSON.stringify(config));
|
||||||
@@ -252,6 +264,14 @@
|
|||||||
$(checkboxEle).checkbox("set unchecked");
|
$(checkboxEle).checkbox("set unchecked");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
}else if (key == "UseProxyProtocol"){
|
||||||
|
let checkboxEle = $("#streamProxyForm input[name=useProxyProtocol]").parent();
|
||||||
|
if (value === true){
|
||||||
|
$(checkboxEle).checkbox("set checked");
|
||||||
|
}else{
|
||||||
|
$(checkboxEle).checkbox("set unchecked");
|
||||||
|
}
|
||||||
|
return;
|
||||||
}else if (key == "ListeningAddress"){
|
}else if (key == "ListeningAddress"){
|
||||||
field = $("#streamProxyForm input[name=listenAddr]");
|
field = $("#streamProxyForm input[name=listenAddr]");
|
||||||
}else if (key == "ProxyTargetAddr"){
|
}else if (key == "ProxyTargetAddr"){
|
||||||
@@ -301,6 +321,7 @@
|
|||||||
proxyAddr: $("#streamProxyForm input[name=proxyAddr]").val().trim(),
|
proxyAddr: $("#streamProxyForm input[name=proxyAddr]").val().trim(),
|
||||||
useTCP: $("#streamProxyForm input[name=useTCP]")[0].checked ,
|
useTCP: $("#streamProxyForm input[name=useTCP]")[0].checked ,
|
||||||
useUDP: $("#streamProxyForm input[name=useUDP]")[0].checked ,
|
useUDP: $("#streamProxyForm input[name=useUDP]")[0].checked ,
|
||||||
|
useProxyProtocol: $("#streamProxyForm input[name=useProxyProtocol]")[0].checked ,
|
||||||
timeout: parseInt($("#streamProxyForm input[name=timeout]").val().trim()),
|
timeout: parseInt($("#streamProxyForm input[name=timeout]").val().trim()),
|
||||||
},
|
},
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
|
@@ -343,7 +343,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(editorSideWrapper).each(function(){
|
$(editorSideWrapper).each(function(){
|
||||||
$(this)[0].contentWindow.setDarkTheme(false);
|
if ($(this)[0].contentWindow.setDarkTheme){
|
||||||
|
$(this)[0].contentWindow.setDarkTheme(false);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if ($("#pluginContextLoader").is(":visible")){
|
if ($("#pluginContextLoader").is(":visible")){
|
||||||
@@ -356,7 +358,9 @@
|
|||||||
$(".sideWrapper iframe")[0].contentWindow.setDarkTheme(true);
|
$(".sideWrapper iframe")[0].contentWindow.setDarkTheme(true);
|
||||||
}
|
}
|
||||||
$(editorSideWrapper).each(function(){
|
$(editorSideWrapper).each(function(){
|
||||||
$(this)[0].contentWindow.setDarkTheme(true);
|
if ($(this)[0].contentWindow.setDarkTheme){
|
||||||
|
$(this)[0].contentWindow.setDarkTheme(true);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if ($("#pluginContextLoader").is(":visible")){
|
if ($("#pluginContextLoader").is(":visible")){
|
||||||
$("#pluginContextLoader")[0].contentWindow.setDarkTheme(true);
|
$("#pluginContextLoader")[0].contentWindow.setDarkTheme(true);
|
||||||
|
Reference in New Issue
Block a user