init commit

+ Added fastly_client_ip to X-Real-IP auto rewrite
+ Updated header rewrite data structure (wip)
+ Added atomic accumulator to TCP proxy
+ Added wip UDP proxy
+ Added white logo for future dark theme
This commit is contained in:
Toby Chui 2024-06-06 11:30:16 +08:00
parent 7193defad7
commit 136d1ecafb
12 changed files with 1702 additions and 27 deletions

View File

@ -52,7 +52,7 @@ var logOutputToFile = flag.Bool("log", true, "Log terminal output to file")
var (
name = "Zoraxy"
version = "3.0.5"
version = "3.0.6"
nodeUUID = "generic"
development = false //Set this to false to use embedded web fs
bootTime = time.Now().Unix()

View File

@ -14,11 +14,16 @@ import (
Main server for dynamic proxy core
Routing Handler Priority (High to Low)
- Blacklist
- Whitelist
- Special Routing Rule (e.g. acme)
- Redirectable
- Subdomain Routing
- Vitrual Directory Routing
- Access Router
- Blacklist
- Whitelist
- Basic Auth
- Vitrual Directory Proxy
- Subdomain Proxy
- Root router (default site router)
*/
func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

View File

@ -304,9 +304,13 @@ func addXForwardedForHeader(req *http.Request) {
if req.Header.Get("X-Real-Ip") == "" {
//Check if CF-Connecting-IP header exists
CF_Connecting_IP := req.Header.Get("CF-Connecting-IP")
Fastly_Client_IP := req.Header.Get("Fastly-Client-IP")
if CF_Connecting_IP != "" {
//Use CF Connecting IP
req.Header.Set("X-Real-Ip", CF_Connecting_IP)
} else if Fastly_Client_IP != "" {
//Use Fastly Client IP
req.Header.Set("X-Real-Ip", Fastly_Client_IP)
} else {
// Not exists. Fill it in with first entry in X-Forwarded-For
ips := strings.Split(clientIP, ",")

View File

@ -72,10 +72,21 @@ type BasicAuthExceptionRule struct {
PathPrefix string
}
// Header injection direction type
type HeaderDirection int
const (
HeaderDirection_ZoraxyToUpstream HeaderDirection = 0 //Inject (or remove) header to request out-going from Zoraxy to backend server
HeaderDirection_ZoraxyToDownstream HeaderDirection = 1 //Inject (or remove) header to request out-going from Zoraxy to client (e.g. browser)
)
// User defined headers to add into a proxy endpoint
type UserDefinedHeader struct {
Key string
Value string
Direction HeaderDirection
Key string
Value string
IsRemove bool //Instead of set, remove this key instead
IsAppend bool //Instead of set, append to the current one with "," as seperator
}
// A Virtual Directory endpoint, provide a subset of ProxyEndpoint for better

View File

@ -9,13 +9,13 @@ import (
"time"
)
//Rewrite url based on proxy root
// Rewrite url based on proxy root (default site)
func RewriteURL(rooturl string, requestURL string) (*url.URL, error) {
rewrittenURL := strings.TrimPrefix(requestURL, rooturl)
return url.Parse(rewrittenURL)
}
//Check if the current platform support web.ssh function
// Check if the current platform support web.ssh function
func IsWebSSHSupported() bool {
//Check if the binary exists in system/gotty/
binary := "gotty_" + runtime.GOOS + "_" + runtime.GOARCH
@ -34,7 +34,7 @@ func IsWebSSHSupported() bool {
return true
}
//Check if a given domain and port is a valid ssh server
// Check if a given domain and port is a valid ssh server
func IsSSHConnectable(ipOrDomain string, port int) bool {
timeout := time.Second * 3
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ipOrDomain, port), timeout)
@ -60,7 +60,7 @@ func IsSSHConnectable(ipOrDomain string, port int) bool {
return string(buf[:7]) == "SSH-2.0"
}
//Check if the port is used by other process or application
// Check if the port is used by other process or application
func isPortInUse(port int) bool {
address := fmt.Sprintf(":%d", port)
listener, err := net.Listen("tcp", address)

View File

@ -7,6 +7,7 @@ import (
"net"
"strconv"
"sync"
"sync/atomic"
"time"
)
@ -38,8 +39,12 @@ func isReachable(target string) bool {
return true
}
func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup, accumulator *int64) {
io.Copy(conn1, conn2)
func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup, accumulator *atomic.Int64) {
n, err := io.Copy(conn1, conn2)
if err != nil {
//Add to accumulator
accumulator.Add(n)
}
conn1.Close()
log.Println("[←]", "close the connect at local:["+conn1.LocalAddr().String()+"] and remote:["+conn1.RemoteAddr().String()+"]")
//conn2.Close()
@ -47,7 +52,7 @@ func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup, accumulator *i
wg.Done()
}
func forward(conn1 net.Conn, conn2 net.Conn, aTob *int64, bToa *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())
var wg sync.WaitGroup
// wait tow goroutines
@ -158,6 +163,8 @@ func (c *ProxyRelayConfig) Start() error {
err = c.Port2port(c.PortA, c.PortB, stopChan)
} else if c.Mode == ProxyMode_Starter {
err = c.Host2host(c.PortA, c.PortB, stopChan)
} else if c.Mode == ProxyMode_UDP {
err = c.ForwardUDP(c.PortA, c.PortB, stopChan)
}
if err != nil {
c.Running = false

View File

@ -3,6 +3,8 @@ package tcpprox
import (
"errors"
"net"
"sync"
"sync/atomic"
"github.com/google/uuid"
"imuslab.com/zoraxy/mod/database"
@ -20,6 +22,7 @@ const (
ProxyMode_Listen = 0
ProxyMode_Transport = 1
ProxyMode_Starter = 2
ProxyMode_UDP = 3
)
type ProxyRelayOptions struct {
@ -31,16 +34,16 @@ type ProxyRelayOptions struct {
}
type ProxyRelayConfig struct {
UUID string //A UUIDv4 representing this config
Name string //Name of the config
Running bool //If the service is running
PortA string //Ports A (config depends on mode)
PortB string //Ports B (config depends on mode)
Mode int //Operation Mode
Timeout int //Timeout for connection in sec
stopChan chan bool //Stop channel to stop the listener
aTobAccumulatedByteTransfer int64 //Accumulated byte transfer from A to B
bToaAccumulatedByteTransfer int64 //Accumulated byte transfer from B to A
UUID string //A UUIDv4 representing this config
Name string //Name of the config
Running bool //If the service is running
PortA string //Ports A (config depends on mode)
PortB string //Ports B (config depends on mode)
Mode int //Operation Mode
Timeout int //Timeout for connection in sec
stopChan chan bool //Stop channel to stop the listener
aTobAccumulatedByteTransfer atomic.Int64 //Accumulated byte transfer from A to B
bToaAccumulatedByteTransfer atomic.Int64 //Accumulated byte transfer from B to A
parent *Manager `json:"-"`
}
@ -57,7 +60,8 @@ type Manager struct {
Configs []*ProxyRelayConfig
//Realtime Statistics
Connections int //currently connected connect counts
Connections int //currently connected connect counts
UDPClientMap sync.Map //map storing the UDP client-server connections
}
func NewTCProxy(options *Options) *Manager {
@ -94,6 +98,11 @@ func NewTCProxy(options *Options) *Manager {
}
func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
//Generate two zero value for atomic int64
aAcc := atomic.Int64{}
bAcc := atomic.Int64{}
aAcc.Store(0)
bAcc.Store(0)
//Generate a new config from options
configUUID := uuid.New().String()
thisConfig := ProxyRelayConfig{
@ -105,8 +114,8 @@ func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
Mode: config.Mode,
Timeout: config.Timeout,
stopChan: nil,
aTobAccumulatedByteTransfer: 0,
bToaAccumulatedByteTransfer: 0,
aTobAccumulatedByteTransfer: aAcc,
bToaAccumulatedByteTransfer: bAcc,
parent: m,
}

View File

@ -0,0 +1,89 @@
package tcpprox
import (
"log"
"net"
)
/*
UDP Proxy Module
*/
// Information maintained for each client/server connection
type udpClientServerConn struct {
ClientAddr *net.UDPAddr // Address of the client
ServerConn *net.UDPConn // UDP connection to server
}
// Generate a new connection by opening a UDP connection to the server
func createNewUDPConn(srvAddr, cliAddr *net.UDPAddr) *udpClientServerConn {
conn := new(udpClientServerConn)
conn.ClientAddr = cliAddr
srvudp, err := net.DialUDP("udp", nil, srvAddr)
if err != nil {
return nil
}
conn.ServerConn = srvudp
return conn
}
// Start listener, return inbound lisener and proxy target UDP address
func initUDPConnections(listenAddr string, targetAddress string) (*net.UDPConn, *net.UDPAddr, error) {
// Set up Proxy
saddr, err := net.ResolveUDPAddr("udp", listenAddr)
if err != nil {
return nil, nil, err
}
inboundConn, err := net.ListenUDP("udp", saddr)
if err != nil {
return nil, nil, err
}
log.Println("Proxy serving on port %s\n", listenAddr)
outboundConn, err := net.ResolveUDPAddr("udp", targetAddress)
if err != nil {
return nil, nil, err
}
return inboundConn, outboundConn, nil
}
func (c *ProxyRelayConfig) ForwardUDP(address1, address2 string, stopChan chan bool) error {
lisener, targetAddr, err := initUDPConnections(address1, address2)
if err != nil {
return err
}
var buffer [1500]byte
for {
n, cliaddr, err := lisener.ReadFromUDP(buffer[0:])
if err != nil {
continue
}
c.aTobAccumulatedByteTransfer.Add(int64(n))
saddr := cliaddr.String()
dlock()
conn, found := ClientDict[saddr]
if !found {
conn = createNewUDPConn(targetAddr, cliaddr)
if conn == nil {
dunlock()
continue
}
ClientDict[saddr] = conn
dunlock()
Vlogf(2, "Created new connection for client %s\n", saddr)
// Fire up routine to manage new connection
go RunConnection(conn)
} else {
Vlogf(5, "Found connection for client %s\n", saddr)
dunlock()
}
// Relay to server
_, err = conn.ServerConn.Write(buffer[0:n])
if checkreport(1, err) {
continue
}
}
}

View File

@ -258,7 +258,7 @@
setTimeout(function(){
//Update the checkbox
msgbox("Proxy Root Updated");
msgbox("Default Site Updated");
}, 100);
})

1512
src/web/img/logo_white.ai Normal file

File diff suppressed because it is too large Load Diff

BIN
src/web/img/logo_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="600px" height="200px" viewBox="0 0 600 200" enable-background="new 0 0 600 200" xml:space="preserve">
<g>
<path fill="#EFEFEF" d="M138.761,47.403l-16.064,17.87c9.504,8.549,15.48,20.94,15.48,34.728c0,13.785-5.976,26.179-15.48,34.726
l16.063,17.871c14.393-12.945,23.445-31.717,23.445-52.597C162.206,79.115,153.155,60.351,138.761,47.403z"/>
<path fill="#EFEFEF" d="M44.198,152.596l16.064-17.869c-9.503-8.547-15.48-20.941-15.48-34.726c0-13.79,5.978-26.179,15.48-34.728
l-16.063-17.87C29.807,60.351,20.753,79.115,20.753,100C20.753,120.881,29.807,139.652,44.198,152.596z"/>
</g>
<polygon fill="#A9D1F3" points="106.581,38.326 91.48,56.48 76.38,38.326 "/>
<polygon fill="#A9D1F3" points="106.581,143.52 91.48,161.674 76.379,143.52 "/>
<circle fill="#A9D1F3" cx="91.48" cy="100" r="22.422"/>
<g>
<path fill="#F7F7F7" d="M194.194,132.898l43.232-66.846h-39.238V54.539h56.155v8.224l-43.233,66.729h43.703v11.629h-60.619V132.898
z"/>
<path fill="#F7F7F7" d="M263.038,108.814c0-21.499,14.45-33.951,30.544-33.951c15.977,0,30.31,12.452,30.31,33.951
c0,21.498-14.333,33.951-30.31,33.951C277.488,142.766,263.038,130.313,263.038,108.814z M310.029,108.814
c0-13.627-6.344-22.791-16.447-22.791c-10.221,0-16.564,9.164-16.564,22.791c0,13.744,6.344,22.674,16.564,22.674
C303.686,131.488,310.029,122.559,310.029,108.814z"/>
<path fill="#F7F7F7" d="M339.869,76.391h11.042l1.176,11.629h0.234c4.582-8.223,11.396-13.156,18.444-13.156
c3.173,0,5.169,0.471,7.166,1.293l-2.35,11.863c-2.349-0.704-3.877-1.057-6.578-1.057c-5.287,0-11.632,3.643-15.626,13.981v40.177
h-13.509V76.391z"/>
<path fill="#F7F7F7" d="M380.868,123.969c0-13.98,11.748-21.146,38.649-24.082c-0.115-7.402-2.819-13.98-12.334-13.98
c-6.813,0-13.158,3.056-18.68,6.578l-5.052-9.162c6.696-4.23,15.742-8.459,26.08-8.459c16.096,0,23.497,10.104,23.497,27.374
v38.884h-11.044l-1.058-7.4h-0.469c-5.875,5.051-12.806,9.045-20.56,9.045C388.739,142.766,380.868,135.365,380.868,123.969z
M419.518,124.322V108.58c-19.147,2.23-25.61,7.166-25.61,14.332c0,6.461,4.348,9.047,10.104,9.047
C409.649,131.959,414.231,129.256,419.518,124.322z"/>
<path fill="#F7F7F7" d="M464.63,107.405l-19.383-31.015h14.686l7.636,13.039c1.996,3.643,3.995,7.285,6.109,10.927h0.587
c1.645-3.642,3.406-7.284,5.287-10.927l6.813-13.039h14.099l-19.386,32.424l20.795,32.307h-14.685l-8.459-13.744
c-2.115-3.76-4.346-7.754-6.697-11.396h-0.586c-1.997,3.643-3.995,7.52-5.992,11.396l-7.518,13.744h-14.098L464.63,107.405z"/>
<path fill="#F7F7F7" d="M508.096,166.85l2.586-10.574c1.176,0.354,3.054,0.939,4.815,0.939c6.932,0,11.045-5.168,13.394-12.1
l1.41-4.463l-25.611-64.262h13.746l11.865,33.363c1.996,5.758,3.993,12.1,5.991,18.209h0.587
c1.645-5.992,3.406-12.334,5.053-18.209l10.456-33.363h13.038l-23.73,68.607c-5.051,13.863-11.865,23.143-25.375,23.143
C512.914,168.141,510.329,167.672,508.096,166.85z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB