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

@@ -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
}
}
}