From c6f7f37aafcc46923b795daac9b34344de15c2fe Mon Sep 17 00:00:00 2001 From: Toby Chui Date: Fri, 7 Jun 2024 01:12:42 +0800 Subject: [PATCH] Added stream proxy UDP support + Added UDP support #147 (wip) + Updated structure for proxy storage + Renamed TCPprox module to streamproxy + Added multi selection for white / blacklist #176 --- src/api.go | 15 +- src/main.go | 6 +- src/mod/{tcpprox => streamproxy}/handler.go | 79 +--- .../tcpprox.go => streamproxy/streamproxy.go} | 161 +++++--- .../streamproxy_test.go} | 8 +- src/mod/streamproxy/tcpprox.go | 146 ++++++++ src/mod/streamproxy/udpprox.go | 157 ++++++++ src/mod/tcpprox/conn.go | 348 ------------------ src/mod/tcpprox/nb.go.ref | 289 --------------- src/mod/tcpprox/udpprox.go | 89 ----- src/mod/utils/utils.go | 4 +- src/start.go | 4 +- src/web/components/access.html | 135 ++++--- .../{tcpprox.html => streamprox.html} | 206 ++++++----- src/web/index.html | 6 +- 15 files changed, 663 insertions(+), 990 deletions(-) rename src/mod/{tcpprox => streamproxy}/handler.go (70%) rename src/mod/{tcpprox/tcpprox.go => streamproxy/streamproxy.go} (51%) rename src/mod/{tcpprox/tcpprox_test.go => streamproxy/streamproxy_test.go} (86%) create mode 100644 src/mod/streamproxy/tcpprox.go create mode 100644 src/mod/streamproxy/udpprox.go delete mode 100644 src/mod/tcpprox/conn.go delete mode 100644 src/mod/tcpprox/nb.go.ref delete mode 100644 src/mod/tcpprox/udpprox.go rename src/web/components/{tcpprox.html => streamprox.html} (67%) diff --git a/src/api.go b/src/api.go index 19b3aa3..f367de2 100644 --- a/src/api.go +++ b/src/api.go @@ -141,14 +141,13 @@ func initAPIs() { authRouter.HandleFunc("/api/gan/members/delete", ganManager.HandleMemberDelete) //TCP Proxy - authRouter.HandleFunc("/api/tcpprox/config/add", tcpProxyManager.HandleAddProxyConfig) - authRouter.HandleFunc("/api/tcpprox/config/edit", tcpProxyManager.HandleEditProxyConfigs) - authRouter.HandleFunc("/api/tcpprox/config/list", tcpProxyManager.HandleListConfigs) - authRouter.HandleFunc("/api/tcpprox/config/start", tcpProxyManager.HandleStartProxy) - authRouter.HandleFunc("/api/tcpprox/config/stop", tcpProxyManager.HandleStopProxy) - authRouter.HandleFunc("/api/tcpprox/config/delete", tcpProxyManager.HandleRemoveProxy) - authRouter.HandleFunc("/api/tcpprox/config/status", tcpProxyManager.HandleGetProxyStatus) - authRouter.HandleFunc("/api/tcpprox/config/validate", tcpProxyManager.HandleConfigValidate) + authRouter.HandleFunc("/api/streamprox/config/add", streamProxyManager.HandleAddProxyConfig) + authRouter.HandleFunc("/api/streamprox/config/edit", streamProxyManager.HandleEditProxyConfigs) + authRouter.HandleFunc("/api/streamprox/config/list", streamProxyManager.HandleListConfigs) + authRouter.HandleFunc("/api/streamprox/config/start", streamProxyManager.HandleStartProxy) + authRouter.HandleFunc("/api/streamprox/config/stop", streamProxyManager.HandleStopProxy) + authRouter.HandleFunc("/api/streamprox/config/delete", streamProxyManager.HandleRemoveProxy) + authRouter.HandleFunc("/api/streamprox/config/status", streamProxyManager.HandleGetProxyStatus) //mDNS APIs authRouter.HandleFunc("/api/mdns/list", HandleMdnsListing) diff --git a/src/main.go b/src/main.go index 5ffa919..6dfae16 100644 --- a/src/main.go +++ b/src/main.go @@ -28,7 +28,7 @@ import ( "imuslab.com/zoraxy/mod/sshprox" "imuslab.com/zoraxy/mod/statistic" "imuslab.com/zoraxy/mod/statistic/analytic" - "imuslab.com/zoraxy/mod/tcpprox" + "imuslab.com/zoraxy/mod/streamproxy" "imuslab.com/zoraxy/mod/tlscert" "imuslab.com/zoraxy/mod/uptime" "imuslab.com/zoraxy/mod/utils" @@ -54,7 +54,7 @@ var ( name = "Zoraxy" version = "3.0.6" 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,7 +79,7 @@ var ( mdnsScanner *mdns.MDNSHost //mDNS discovery services ganManager *ganserv.NetworkManager //Global Area Network Manager webSshManager *sshprox.Manager //Web SSH connection service - tcpProxyManager *tcpprox.Manager //TCP Proxy Manager + streamProxyManager *streamproxy.Manager //Stream Proxy Manager for TCP / UDP forwarding 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 diff --git a/src/mod/tcpprox/handler.go b/src/mod/streamproxy/handler.go similarity index 70% rename from src/mod/tcpprox/handler.go rename to src/mod/streamproxy/handler.go index 2b73869..bc78148 100644 --- a/src/mod/tcpprox/handler.go +++ b/src/mod/streamproxy/handler.go @@ -1,9 +1,10 @@ -package tcpprox +package streamproxy import ( "encoding/json" "net/http" "strconv" + "strings" "imuslab.com/zoraxy/mod/utils" ) @@ -22,13 +23,13 @@ func (m *Manager) HandleAddProxyConfig(w http.ResponseWriter, r *http.Request) { return } - portA, err := utils.PostPara(r, "porta") + listenAddr, err := utils.PostPara(r, "listenAddr") if err != nil { utils.SendErrorResponse(w, "first address cannot be empty") return } - portB, err := utils.PostPara(r, "portb") + proxyAddr, err := utils.PostPara(r, "proxyAddr") if err != nil { utils.SendErrorResponse(w, "second address cannot be empty") return @@ -44,27 +45,17 @@ func (m *Manager) HandleAddProxyConfig(w http.ResponseWriter, r *http.Request) { } } - modeValue := ProxyMode_Transport - mode, err := utils.PostPara(r, "mode") - if err != nil || mode == "" { - utils.SendErrorResponse(w, "no mode given") - } else if mode == "listen" { - modeValue = ProxyMode_Listen - } else if mode == "transport" { - modeValue = ProxyMode_Transport - } else if mode == "starter" { - modeValue = ProxyMode_Starter - } else { - utils.SendErrorResponse(w, "invalid mode given. Only support listen / transport / starter") - } + useTCP, _ := utils.PostBool(r, "useTCP") + useUDP, _ := utils.PostBool(r, "useUDP") //Create the target config newConfigUUID := m.NewConfig(&ProxyRelayOptions{ - Name: name, - PortA: portA, - PortB: portB, - Timeout: timeout, - Mode: modeValue, + Name: name, + ListeningAddr: strings.TrimSpace(listenAddr), + ProxyAddr: strings.TrimSpace(proxyAddr), + Timeout: timeout, + UseTCP: useTCP, + UseUDP: useUDP, }) js, _ := json.Marshal(newConfigUUID) @@ -80,22 +71,10 @@ func (m *Manager) HandleEditProxyConfigs(w http.ResponseWriter, r *http.Request) } newName, _ := utils.PostPara(r, "name") - newPortA, _ := utils.PostPara(r, "porta") - newPortB, _ := utils.PostPara(r, "portb") - newModeStr, _ := utils.PostPara(r, "mode") - newMode := -1 - if newModeStr != "" { - if newModeStr == "listen" { - newMode = 0 - } else if newModeStr == "transport" { - newMode = 1 - } else if newModeStr == "starter" { - newMode = 2 - } else { - utils.SendErrorResponse(w, "invalid new mode value") - return - } - } + listenAddr, _ := utils.PostPara(r, "listenAddr") + proxyAddr, _ := utils.PostPara(r, "proxyAddr") + useTCP, _ := utils.PostBool(r, "useTCP") + useUDP, _ := utils.PostBool(r, "useUDP") newTimeoutStr, _ := utils.PostPara(r, "timeout") newTimeout := -1 @@ -108,7 +87,7 @@ func (m *Manager) HandleEditProxyConfigs(w http.ResponseWriter, r *http.Request) } // Call the EditConfig method to modify the configuration - err = m.EditConfig(configUUID, newName, newPortA, newPortB, newMode, newTimeout) + err = m.EditConfig(configUUID, newName, listenAddr, proxyAddr, useTCP, useUDP, newTimeout) if err != nil { utils.SendErrorResponse(w, err.Error()) return @@ -158,6 +137,7 @@ func (m *Manager) HandleStopProxy(w http.ResponseWriter, r *http.Request) { } if !targetProxyConfig.IsRunning() { + targetProxyConfig.Running = false utils.SendErrorResponse(w, "target proxy service is not running") return } @@ -180,6 +160,7 @@ func (m *Manager) HandleRemoveProxy(w http.ResponseWriter, r *http.Request) { } if targetProxyConfig.IsRunning() { + targetProxyConfig.Running = false utils.SendErrorResponse(w, "Service is running") return } @@ -209,25 +190,3 @@ func (m *Manager) HandleGetProxyStatus(w http.ResponseWriter, r *http.Request) { js, _ := json.Marshal(targetConfig) utils.SendJSONResponse(w, string(js)) } - -func (m *Manager) HandleConfigValidate(w http.ResponseWriter, r *http.Request) { - uuid, err := utils.GetPara(r, "uuid") - if err != nil { - utils.SendErrorResponse(w, "invalid uuid given") - return - } - - targetConfig, err := m.GetConfigByUUID(uuid) - if err != nil { - utils.SendErrorResponse(w, err.Error()) - return - } - - err = targetConfig.ValidateConfigs() - if err != nil { - utils.SendErrorResponse(w, err.Error()) - return - } - - utils.SendOK(w) -} diff --git a/src/mod/tcpprox/tcpprox.go b/src/mod/streamproxy/streamproxy.go similarity index 51% rename from src/mod/tcpprox/tcpprox.go rename to src/mod/streamproxy/streamproxy.go index f030bdf..1084379 100644 --- a/src/mod/tcpprox/tcpprox.go +++ b/src/mod/streamproxy/streamproxy.go @@ -1,7 +1,8 @@ -package tcpprox +package streamproxy import ( "errors" + "log" "net" "sync" "sync/atomic" @@ -18,34 +19,31 @@ import ( connection */ -const ( - ProxyMode_Listen = 0 - ProxyMode_Transport = 1 - ProxyMode_Starter = 2 - ProxyMode_UDP = 3 -) - type ProxyRelayOptions struct { - Name string - PortA string - PortB string - Timeout int - Mode int + Name string + ListeningAddr string + ProxyAddr string + Timeout int + UseTCP bool + UseUDP bool } 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 + 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 Timeout int //Timeout for connection in sec - stopChan chan bool //Stop channel to stop the listener + tcpStopChan chan bool //Stop channel for TCP listener + udpStopChan chan bool //Stop channel for UDP listener aTobAccumulatedByteTransfer atomic.Int64 //Accumulated byte transfer from A to B bToaAccumulatedByteTransfer atomic.Int64 //Accumulated byte transfer from B to A - - parent *Manager `json:"-"` + udpClientMap sync.Map //map storing the UDP client-server connections + parent *Manager `json:"-"` } type Options struct { @@ -60,11 +58,11 @@ type Manager struct { Configs []*ProxyRelayConfig //Realtime Statistics - Connections int //currently connected connect counts - UDPClientMap sync.Map //map storing the UDP client-server connections + Connections int //currently connected connect counts + } -func NewTCProxy(options *Options) *Manager { +func NewStreamProxy(options *Options) *Manager { options.Database.NewTable("tcprox") //Load relay configs from db @@ -108,16 +106,17 @@ func (m *Manager) NewConfig(config *ProxyRelayOptions) string { thisConfig := ProxyRelayConfig{ UUID: configUUID, Name: config.Name, - Running: false, - PortA: config.PortA, - PortB: config.PortB, - Mode: config.Mode, + ListeningAddress: config.ListeningAddr, + ProxyTargetAddr: config.ProxyAddr, + UseTCP: config.UseTCP, + UseUDP: config.UseUDP, Timeout: config.Timeout, - stopChan: nil, + tcpStopChan: nil, + udpStopChan: nil, aTobAccumulatedByteTransfer: aAcc, bToaAccumulatedByteTransfer: bAcc, - - parent: m, + udpClientMap: sync.Map{}, + parent: m, } m.Configs = append(m.Configs, &thisConfig) m.SaveConfigToDatabase() @@ -135,7 +134,7 @@ func (m *Manager) GetConfigByUUID(configUUID string) (*ProxyRelayConfig, error) } // Edit the config based on config UUID, leave empty for unchange fields -func (m *Manager) EditConfig(configUUID string, newName string, newPortA string, newPortB string, newMode int, newTimeout int) error { +func (m *Manager) EditConfig(configUUID string, newName string, newListeningAddr string, newProxyAddr string, useTCP bool, useUDP bool, newTimeout int) error { // Find the config with the specified UUID foundConfig, err := m.GetConfigByUUID(configUUID) if err != nil { @@ -146,18 +145,16 @@ func (m *Manager) EditConfig(configUUID string, newName string, newPortA string, if newName != "" { foundConfig.Name = newName } - if newPortA != "" { - foundConfig.PortA = newPortA + if newListeningAddr != "" { + foundConfig.ListeningAddress = newListeningAddr } - if newPortB != "" { - foundConfig.PortB = newPortB - } - if newMode != -1 { - if newMode > 2 || newMode < 0 { - return errors.New("invalid mode given") - } - foundConfig.Mode = newMode + if newProxyAddr != "" { + foundConfig.ProxyTargetAddr = newProxyAddr } + + foundConfig.UseTCP = useTCP + foundConfig.UseUDP = useUDP + if newTimeout != -1 { if newTimeout < 0 { return errors.New("invalid timeout value given") @@ -165,13 +162,6 @@ func (m *Manager) EditConfig(configUUID string, newName string, newPortA string, foundConfig.Timeout = newTimeout } - /* - err = foundConfig.ValidateConfigs() - if err != nil { - return err - } - */ - m.SaveConfigToDatabase() return nil @@ -192,3 +182,78 @@ func (m *Manager) RemoveConfig(configUUID string) error { func (m *Manager) SaveConfigToDatabase() { m.Options.Database.Write("tcprox", "rules", m.Configs) } + +/* + 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) + c.tcpStopChan = tcpStopChan + + udpStopChan := make(chan bool) + c.udpStopChan = udpStopChan + + //Start the proxy service + if c.UseUDP { + go func() { + if !c.UseTCP { + //By default running state shows TCP proxy. If TCP is not in use, UDP is shown instead + c.Running = true + } + err := c.ForwardUDP(c.ListeningAddress, c.ProxyTargetAddr, udpStopChan) + if err != nil { + if !c.UseTCP { + c.Running = false + } + log.Println("[TCP] Error starting stream proxy " + c.Name + "(" + c.UUID + "): " + err.Error()) + } + }() + } + + if c.UseTCP { + go func() { + //Default to transport mode + c.Running = true + err := c.Port2host(c.ListeningAddress, c.ProxyTargetAddr, tcpStopChan) + if err != nil { + c.Running = false + log.Println("[TCP] Error starting stream proxy " + c.Name + "(" + c.UUID + "): " + err.Error()) + } + }() + } + + //Successfully spawned off the proxy routine + + return nil +} + +// Stop a running proxy if running +func (c *ProxyRelayConfig) IsRunning() bool { + return c.tcpStopChan != nil || c.udpStopChan != nil +} + +// Stop a running proxy if running +func (c *ProxyRelayConfig) Stop() { + log.Println("[PROXY] Stopping Stream Proxy " + c.Name) + + if c.udpStopChan != nil { + c.udpStopChan <- true + c.udpStopChan = nil + } + + if c.tcpStopChan != nil { + c.tcpStopChan <- true + c.tcpStopChan = nil + } + + log.Println("[PROXY] Stopped Stream Proxy " + c.Name) + c.Running = false +} diff --git a/src/mod/tcpprox/tcpprox_test.go b/src/mod/streamproxy/streamproxy_test.go similarity index 86% rename from src/mod/tcpprox/tcpprox_test.go rename to src/mod/streamproxy/streamproxy_test.go index 0dd3cdf..a9ccb04 100644 --- a/src/mod/tcpprox/tcpprox_test.go +++ b/src/mod/streamproxy/streamproxy_test.go @@ -1,10 +1,10 @@ -package tcpprox_test +package streamproxy_test import ( "testing" "time" - "imuslab.com/zoraxy/mod/tcpprox" + "imuslab.com/zoraxy/mod/streamproxy" ) func TestPort2Port(t *testing.T) { @@ -12,7 +12,7 @@ func TestPort2Port(t *testing.T) { stopChan := make(chan bool) // Create a ProxyRelayConfig with dummy values - config := &tcpprox.ProxyRelayConfig{ + config := &streamproxy.ProxyRelayConfig{ Timeout: 1, } @@ -36,7 +36,7 @@ func TestPort2Port(t *testing.T) { time.Sleep(1 * time.Second) // If the goroutine is still running, it means it did not stop as expected - if config.Running { + if config.IsRunning() { t.Errorf("port2port did not stop as expected") } diff --git a/src/mod/streamproxy/tcpprox.go b/src/mod/streamproxy/tcpprox.go new file mode 100644 index 0000000..6fcaed0 --- /dev/null +++ b/src/mod/streamproxy/tcpprox.go @@ -0,0 +1,146 @@ +package streamproxy + +import ( + "errors" + "io" + "log" + "net" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) + +func isValidIP(ip string) bool { + parsedIP := net.ParseIP(ip) + return parsedIP != nil +} + +func isValidPort(port string) bool { + portInt, err := strconv.Atoi(port) + if err != nil { + return false + } + + if portInt < 1 || portInt > 65535 { + return false + } + + return true +} + +func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup, accumulator *atomic.Int64) { + n, err := io.Copy(conn1, conn2) + if err != nil { + return + } + accumulator.Add(n) //Add to accumulator + conn1.Close() + log.Println("[←]", "close the connect at local:["+conn1.LocalAddr().String()+"] and remote:["+conn1.RemoteAddr().String()+"]") + //conn2.Close() + //log.Println("[←]", "close the connect at local:["+conn2.LocalAddr().String()+"] and remote:["+conn2.RemoteAddr().String()+"]") + wg.Done() +} + +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 + wg.Add(2) + go connCopy(conn1, conn2, &wg, aTob) + go connCopy(conn2, conn1, &wg, bToa) + //blocking when the wg is locked + wg.Wait() +} + +func (c *ProxyRelayConfig) accept(listener net.Listener) (net.Conn, error) { + conn, err := listener.Accept() + if err != nil { + return nil, err + } + + //Check if connection in blacklist or whitelist + if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { + if !c.parent.Options.AccessControlHandler(conn) { + time.Sleep(300 * time.Millisecond) + conn.Close() + log.Println("[x]", "Connection from "+addr.IP.String()+" rejected by access control policy") + return nil, errors.New("Connection from " + addr.IP.String() + " rejected by access control policy") + } + } + + log.Println("[√]", "accept a new client. remote address:["+conn.RemoteAddr().String()+"], local address:["+conn.LocalAddr().String()+"]") + return conn, err +} + +func startListener(address string) (net.Listener, error) { + log.Println("[+]", "try to start server on:["+address+"]") + server, err := net.Listen("tcp", address) + if err != nil { + return nil, errors.New("listen address [" + address + "] faild") + } + log.Println("[√]", "start listen at address:["+address+"]") + return server, nil +} + +/* + Forwarder Functions +*/ + +/* +portA -> server +server -> portB +*/ +func (c *ProxyRelayConfig) Port2host(allowPort string, targetAddress string, stopChan chan bool) error { + listenerStartingAddr := allowPort + if isValidPort(allowPort) { + //number only, e.g. 8080 + listenerStartingAddr = "0.0.0.0:" + allowPort + } else if strings.HasPrefix(allowPort, ":") && isValidPort(allowPort[1:]) { + //port number starting with :, e.g. :8080 + listenerStartingAddr = "0.0.0.0" + allowPort + } + + server, err := startListener(listenerStartingAddr) + if err != nil { + return err + } + + targetAddress = strings.TrimSpace(targetAddress) + + //Start stop handler + go func() { + <-stopChan + log.Println("[x]", "Received stop signal. Exiting Port to Host forwarder") + server.Close() + }() + + //Start blocking loop for accepting connections + for { + conn, err := c.accept(server) + if err != nil { + if errors.Is(err, net.ErrClosed) { + //Terminate by stop chan. Exit listener loop + return nil + } + //Connection error. Retry + continue + } + + go func(targetAddress string) { + log.Println("[+]", "start connect host:["+targetAddress+"]") + target, err := net.Dial("tcp", targetAddress) + if err != nil { + // temporarily unavailable, don't use fatal. + log.Println("[x]", "connect target address ["+targetAddress+"] faild. retry in ", c.Timeout, "seconds. ") + 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 + } + log.Println("[→]", "connect target address ["+targetAddress+"] success.") + forward(target, conn, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer) + }(targetAddress) + } +} diff --git a/src/mod/streamproxy/udpprox.go b/src/mod/streamproxy/udpprox.go new file mode 100644 index 0000000..08ee676 --- /dev/null +++ b/src/mod/streamproxy/udpprox.go @@ -0,0 +1,157 @@ +package streamproxy + +import ( + "errors" + "log" + "net" + "strings" + "time" +) + +/* + 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("[UDP] Proxy listening on " + listenAddr) + + outboundConn, err := net.ResolveUDPAddr("udp", targetAddress) + if err != nil { + return nil, nil, err + } + + return inboundConn, outboundConn, nil +} + +// Go routine which manages connection from server to single client +func (c *ProxyRelayConfig) RunUDPConnectionRelay(conn *udpClientServerConn, lisenter *net.UDPConn) { + var buffer [1500]byte + for { + // Read from server + n, err := conn.ServerConn.Read(buffer[0:]) + if err != nil { + if errors.Is(err, net.ErrClosed) { + return + } + continue + } + // Relay it to client + _, err = lisenter.WriteToUDP(buffer[0:n], conn.ClientAddr) + if err != nil { + continue + } + + } +} + +// Close all connections that waiting for read from server +func (c *ProxyRelayConfig) CloseAllUDPConnections() { + c.udpClientMap.Range(func(clientAddr, clientServerConn interface{}) bool { + conn := clientServerConn.(*udpClientServerConn) + conn.ServerConn.Close() + return true + }) +} + +func (c *ProxyRelayConfig) ForwardUDP(address1, address2 string, stopChan chan bool) error { + //By default the incoming listen Address is int + //We need to add the loopback address into it + if isValidPort(address1) { + //Port number only. Missing the : in front + address1 = ":" + address1 + } + if strings.HasPrefix(address1, ":") { + //Prepend 127.0.0.1 to the address + address1 = "127.0.0.1" + address1 + } + + lisener, targetAddr, err := initUDPConnections(address1, address2) + if err != nil { + return err + } + + go func() { + //Stop channel receiver + for { + select { + case <-stopChan: + //Stop signal received + //Stop server -> client forwarder + c.CloseAllUDPConnections() + //Stop client -> server forwarder + //Force close, will terminate ReadFromUDP for inbound listener + lisener.Close() + return + default: + time.Sleep(100 * time.Millisecond) + } + } + + }() + + var buffer [1500]byte + for { + n, cliaddr, err := lisener.ReadFromUDP(buffer[0:]) + if err != nil { + if errors.Is(err, net.ErrClosed) { + //Proxy stopped + return nil + } + continue + } + c.aTobAccumulatedByteTransfer.Add(int64(n)) + saddr := cliaddr.String() + rawConn, found := c.udpClientMap.Load(saddr) + var conn *udpClientServerConn + if !found { + conn = createNewUDPConn(targetAddr, cliaddr) + if conn == nil { + continue + } + c.udpClientMap.Store(saddr, conn) + log.Println("[UDP] Created new connection for client " + saddr) + // Fire up routine to manage new connection + go c.RunUDPConnectionRelay(conn, lisener) + + } else { + log.Println("[UDP] Found connection for client " + saddr) + conn = rawConn.(*udpClientServerConn) + } + + // Relay to server + _, err = conn.ServerConn.Write(buffer[0:n]) + if err != nil { + continue + } + + } +} diff --git a/src/mod/tcpprox/conn.go b/src/mod/tcpprox/conn.go deleted file mode 100644 index 2f53f70..0000000 --- a/src/mod/tcpprox/conn.go +++ /dev/null @@ -1,348 +0,0 @@ -package tcpprox - -import ( - "errors" - "io" - "log" - "net" - "strconv" - "sync" - "sync/atomic" - "time" -) - -func isValidIP(ip string) bool { - parsedIP := net.ParseIP(ip) - return parsedIP != nil -} - -func isValidPort(port string) bool { - portInt, err := strconv.Atoi(port) - if err != nil { - return false - } - - if portInt < 1 || portInt > 65535 { - return false - } - - return true -} - -func isReachable(target string) bool { - timeout := time.Duration(2 * time.Second) // Set the timeout value as per your requirement - conn, err := net.DialTimeout("tcp", target, timeout) - if err != nil { - return false - } - defer conn.Close() - return true -} - -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() - //log.Println("[←]", "close the connect at local:["+conn2.LocalAddr().String()+"] and remote:["+conn2.RemoteAddr().String()+"]") - wg.Done() -} - -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 - wg.Add(2) - go connCopy(conn1, conn2, &wg, aTob) - go connCopy(conn2, conn1, &wg, bToa) - //blocking when the wg is locked - wg.Wait() -} - -func (c *ProxyRelayConfig) accept(listener net.Listener) (net.Conn, error) { - - conn, err := listener.Accept() - if err != nil { - return nil, err - } - - //Check if connection in blacklist or whitelist - if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { - if !c.parent.Options.AccessControlHandler(conn) { - time.Sleep(300 * time.Millisecond) - conn.Close() - log.Println("[x]", "Connection from "+addr.IP.String()+" rejected by access control policy") - return nil, errors.New("Connection from " + addr.IP.String() + " rejected by access control policy") - } - } - - log.Println("[√]", "accept a new client. remote address:["+conn.RemoteAddr().String()+"], local address:["+conn.LocalAddr().String()+"]") - return conn, err -} - -func startListener(address string) (net.Listener, error) { - log.Println("[+]", "try to start server on:["+address+"]") - server, err := net.Listen("tcp", address) - if err != nil { - return nil, errors.New("listen address [" + address + "] faild") - } - log.Println("[√]", "start listen at address:["+address+"]") - return server, nil -} - -/* - Config Functions -*/ - -// Config validator -func (c *ProxyRelayConfig) ValidateConfigs() error { - if c.Mode == ProxyMode_Transport { - //Port2Host: PortA int, PortB string - if !isValidPort(c.PortA) { - return errors.New("first address must be a valid port number") - } - - if !isReachable(c.PortB) { - return errors.New("second address is unreachable") - } - return nil - - } else if c.Mode == ProxyMode_Listen { - //Port2Port: Both port are port number - if !isValidPort(c.PortA) { - return errors.New("first address is not a valid port number") - } - - if !isValidPort(c.PortB) { - return errors.New("second address is not a valid port number") - } - - return nil - } else if c.Mode == ProxyMode_Starter { - //Host2Host: Both have to be hosts - if !isReachable(c.PortA) { - return errors.New("first address is unreachable") - } - - if !isReachable(c.PortB) { - return errors.New("second address is unreachable") - } - - return nil - } else { - return errors.New("invalid mode given") - } -} - -// Start a proxy if stopped -func (c *ProxyRelayConfig) Start() error { - if c.Running { - return errors.New("proxy already running") - } - - // Create a stopChan to control the loop - stopChan := make(chan bool) - c.stopChan = stopChan - - //Validate configs - err := c.ValidateConfigs() - if err != nil { - return err - } - - //Start the proxy service - go func() { - c.Running = true - if c.Mode == ProxyMode_Transport { - err = c.Port2host(c.PortA, c.PortB, stopChan) - } else if c.Mode == ProxyMode_Listen { - 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 - log.Println("Error starting proxy service " + c.Name + "(" + c.UUID + "): " + err.Error()) - } - }() - - //Successfully spawned off the proxy routine - return nil -} - -// Stop a running proxy if running -func (c *ProxyRelayConfig) IsRunning() bool { - return c.Running || c.stopChan != nil -} - -// Stop a running proxy if running -func (c *ProxyRelayConfig) Stop() { - if c.Running || c.stopChan != nil { - c.stopChan <- true - time.Sleep(300 * time.Millisecond) - c.stopChan = nil - c.Running = false - } -} - -/* - Forwarder Functions -*/ - -/* -portA -> server -portB -> server -*/ -func (c *ProxyRelayConfig) Port2port(port1 string, port2 string, stopChan chan bool) error { - //Trim the Prefix of : if exists - listen1, err := startListener("0.0.0.0:" + port1) - if err != nil { - return err - } - listen2, err := startListener("0.0.0.0:" + port2) - if err != nil { - return err - } - - log.Println("[√]", "listen port:", port1, "and", port2, "success. waiting for client...") - c.Running = true - - go func() { - <-stopChan - log.Println("[x]", "Received stop signal. Exiting Port to Port forwarder") - c.Running = false - listen1.Close() - listen2.Close() - }() - - for { - conn1, err := c.accept(listen1) - if err != nil { - if !c.Running { - return nil - } - continue - } - - conn2, err := c.accept(listen2) - if err != nil { - if !c.Running { - return nil - } - continue - } - - if conn1 == nil || conn2 == nil { - log.Println("[x]", "accept client faild. retry in ", c.Timeout, " seconds. ") - time.Sleep(time.Duration(c.Timeout) * time.Second) - continue - } - go forward(conn1, conn2, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer) - } -} - -/* -portA -> server -server -> portB -*/ -func (c *ProxyRelayConfig) Port2host(allowPort string, targetAddress string, stopChan chan bool) error { - server, err := startListener("0.0.0.0:" + allowPort) - if err != nil { - return err - } - - //Start stop handler - go func() { - <-stopChan - log.Println("[x]", "Received stop signal. Exiting Port to Host forwarder") - c.Running = false - server.Close() - }() - - //Start blocking loop for accepting connections - for { - conn, err := c.accept(server) - if conn == nil || err != nil { - if !c.Running { - //Terminate by stop chan. Exit listener loop - return nil - } - - //Connection error. Retry - continue - } - - go func(targetAddress string) { - log.Println("[+]", "start connect host:["+targetAddress+"]") - target, err := net.Dial("tcp", targetAddress) - if err != nil { - // temporarily unavailable, don't use fatal. - log.Println("[x]", "connect target address ["+targetAddress+"] faild. retry in ", c.Timeout, "seconds. ") - 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 - } - log.Println("[→]", "connect target address ["+targetAddress+"] success.") - forward(target, conn, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer) - }(targetAddress) - } -} - -/* -server -> portA -server -> portB -*/ -func (c *ProxyRelayConfig) Host2host(address1, address2 string, stopChan chan bool) error { - c.Running = true - go func() { - <-stopChan - log.Println("[x]", "Received stop signal. Exiting Host to Host forwarder") - c.Running = false - }() - - for c.Running { - log.Println("[+]", "try to connect host:["+address1+"] and ["+address2+"]") - var host1, host2 net.Conn - var err error - for { - d := net.Dialer{Timeout: time.Duration(c.Timeout)} - host1, err = d.Dial("tcp", address1) - if err == nil { - log.Println("[→]", "connect ["+address1+"] success.") - break - } else { - log.Println("[x]", "connect target address ["+address1+"] faild. retry in ", c.Timeout, " seconds. ") - time.Sleep(time.Duration(c.Timeout) * time.Second) - } - - if !c.Running { - return nil - } - } - for { - d := net.Dialer{Timeout: time.Duration(c.Timeout)} - host2, err = d.Dial("tcp", address2) - if err == nil { - log.Println("[→]", "connect ["+address2+"] success.") - break - } else { - log.Println("[x]", "connect target address ["+address2+"] faild. retry in ", c.Timeout, " seconds. ") - time.Sleep(time.Duration(c.Timeout) * time.Second) - } - - if !c.Running { - return nil - } - } - go forward(host1, host2, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer) - } - - return nil -} diff --git a/src/mod/tcpprox/nb.go.ref b/src/mod/tcpprox/nb.go.ref deleted file mode 100644 index 6335766..0000000 --- a/src/mod/tcpprox/nb.go.ref +++ /dev/null @@ -1,289 +0,0 @@ -package tcpprox - -import ( - "fmt" - "io" - "log" - "net" - "os" - "regexp" - "strconv" - "strings" - "sync" - "time" -) - -const timeout = 5 - -func main() { - //log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile) - log.SetFlags(log.Ldate | log.Lmicroseconds) - - printWelcome() - - args := os.Args - argc := len(os.Args) - if argc <= 2 { - printHelp() - os.Exit(0) - } - - //TODO:support UDP protocol - - /*var logFileError error - if argc > 5 && args[4] == "-log" { - logPath := args[5] + "/" + time.Now().Format("2006_01_02_15_04_05") // "2006-01-02 15:04:05" - logPath += args[1] + "-" + strings.Replace(args[2], ":", "_", -1) + "-" + args[3] + ".log" - logPath = strings.Replace(logPath, `\`, "/", -1) - logPath = strings.Replace(logPath, "//", "/", -1) - logFile, logFileError = os.OpenFile(logPath, os.O_APPEND|os.O_CREATE, 0666) - if logFileError != nil { - log.Fatalln("[x]", "log file path error.", logFileError.Error()) - } - log.Println("[√]", "open test log file success. path:", logPath) - }*/ - - switch args[1] { - case "-listen": - if argc < 3 { - log.Fatalln(`-listen need two arguments, like "nb -listen 1997 2017".`) - } - port1 := checkPort(args[2]) - port2 := checkPort(args[3]) - log.Println("[√]", "start to listen port:", port1, "and port:", port2) - port2port(port1, port2) - break - case "-tran": - if argc < 3 { - log.Fatalln(`-tran need two arguments, like "nb -tran 1997 192.168.1.2:3389".`) - } - port := checkPort(args[2]) - var remoteAddress string - if checkIp(args[3]) { - remoteAddress = args[3] - } - split := strings.SplitN(remoteAddress, ":", 2) - log.Println("[√]", "start to transmit address:", remoteAddress, "to address:", split[0]+":"+port) - port2host(port, remoteAddress) - break - case "-slave": - if argc < 3 { - log.Fatalln(`-slave need two arguments, like "nb -slave 127.0.0.1:3389 8.8.8.8:1997".`) - } - var address1, address2 string - checkIp(args[2]) - if checkIp(args[2]) { - address1 = args[2] - } - checkIp(args[3]) - if checkIp(args[3]) { - address2 = args[3] - } - log.Println("[√]", "start to connect address:", address1, "and address:", address2) - host2host(address1, address2) - break - default: - printHelp() - } -} - -func printWelcome() { - fmt.Println("+----------------------------------------------------------------+") - fmt.Println("| Welcome to use NATBypass Ver1.0.0 . |") - fmt.Println("| Code by cw1997 at 2017-10-19 03:59:51 |") - fmt.Println("| If you have some problem when you use the tool, |") - fmt.Println("| please submit issue at : https://github.com/cw1997/NATBypass . |") - fmt.Println("+----------------------------------------------------------------+") - fmt.Println() - // sleep one second because the fmt is not thread-safety. - // if not to do this, fmt.Print will print after the log.Print. - time.Sleep(time.Second) -} -func printHelp() { - fmt.Println(`usage: "-listen port1 port2" example: "nb -listen 1997 2017" `) - fmt.Println(` "-tran port1 ip:port2" example: "nb -tran 1997 192.168.1.2:3389" `) - fmt.Println(` "-slave ip1:port1 ip2:port2" example: "nb -slave 127.0.0.1:3389 8.8.8.8:1997" `) - fmt.Println(`============================================================`) - fmt.Println(`optional argument: "-log logpath" . example: "nb -listen 1997 2017 -log d:/nb" `) - fmt.Println(`log filename format: Y_m_d_H_i_s-agrs1-args2-args3.log`) - fmt.Println(`============================================================`) - fmt.Println(`if you want more help, please read "README.md". `) -} - -func checkPort(port string) string { - PortNum, err := strconv.Atoi(port) - if err != nil { - log.Fatalln("[x]", "port should be a number") - } - if PortNum < 1 || PortNum > 65535 { - log.Fatalln("[x]", "port should be a number and the range is [1,65536)") - } - return port -} - -func checkIp(address string) bool { - ipAndPort := strings.Split(address, ":") - if len(ipAndPort) != 2 { - log.Fatalln("[x]", "address error. should be a string like [ip:port]. ") - } - ip := ipAndPort[0] - port := ipAndPort[1] - checkPort(port) - pattern := `^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$` - ok, err := regexp.MatchString(pattern, ip) - if err != nil || !ok { - log.Fatalln("[x]", "ip error. ") - } - return ok -} - -func port2port(port1 string, port2 string) { - listen1 := start_server("0.0.0.0:" + port1) - listen2 := start_server("0.0.0.0:" + port2) - log.Println("[√]", "listen port:", port1, "and", port2, "success. waiting for client...") - for { - conn1 := accept(listen1) - conn2 := accept(listen2) - if conn1 == nil || conn2 == nil { - log.Println("[x]", "accept client faild. retry in ", timeout, " seconds. ") - time.Sleep(timeout * time.Second) - continue - } - forward(conn1, conn2) - } -} - -func port2host(allowPort string, targetAddress string) { - server := start_server("0.0.0.0:" + allowPort) - for { - conn := accept(server) - if conn == nil { - continue - } - //println(targetAddress) - go func(targetAddress string) { - log.Println("[+]", "start connect host:["+targetAddress+"]") - target, err := net.Dial("tcp", targetAddress) - if err != nil { - // temporarily unavailable, don't use fatal. - log.Println("[x]", "connect target address ["+targetAddress+"] faild. retry in ", timeout, "seconds. ") - conn.Close() - log.Println("[←]", "close the connect at local:["+conn.LocalAddr().String()+"] and remote:["+conn.RemoteAddr().String()+"]") - time.Sleep(timeout * time.Second) - return - } - log.Println("[→]", "connect target address ["+targetAddress+"] success.") - forward(target, conn) - }(targetAddress) - } -} - -func host2host(address1, address2 string) { - for { - log.Println("[+]", "try to connect host:["+address1+"] and ["+address2+"]") - var host1, host2 net.Conn - var err error - for { - host1, err = net.Dial("tcp", address1) - if err == nil { - log.Println("[→]", "connect ["+address1+"] success.") - break - } else { - log.Println("[x]", "connect target address ["+address1+"] faild. retry in ", timeout, " seconds. ") - time.Sleep(timeout * time.Second) - } - } - for { - host2, err = net.Dial("tcp", address2) - if err == nil { - log.Println("[→]", "connect ["+address2+"] success.") - break - } else { - log.Println("[x]", "connect target address ["+address2+"] faild. retry in ", timeout, " seconds. ") - time.Sleep(timeout * time.Second) - } - } - forward(host1, host2) - } -} - -func start_server(address string) net.Listener { - log.Println("[+]", "try to start server on:["+address+"]") - server, err := net.Listen("tcp", address) - if err != nil { - log.Fatalln("[x]", "listen address ["+address+"] faild.") - } - log.Println("[√]", "start listen at address:["+address+"]") - return server - /*defer server.Close() - - for { - conn, err := server.Accept() - log.Println("accept a new client. remote address:[" + conn.RemoteAddr().String() + - "], local address:[" + conn.LocalAddr().String() + "]") - if err != nil { - log.Println("accept a new client faild.", err.Error()) - continue - } - //go recvConnMsg(conn) - }*/ -} - -func accept(listener net.Listener) net.Conn { - conn, err := listener.Accept() - if err != nil { - log.Println("[x]", "accept connect ["+conn.RemoteAddr().String()+"] faild.", err.Error()) - return nil - } - log.Println("[√]", "accept a new client. remote address:["+conn.RemoteAddr().String()+"], local address:["+conn.LocalAddr().String()+"]") - return conn -} - -func forward(conn1 net.Conn, conn2 net.Conn) { - 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 - wg.Add(2) - go connCopy(conn1, conn2, &wg) - go connCopy(conn2, conn1, &wg) - //blocking when the wg is locked - wg.Wait() -} - -func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup) { - //TODO:log, record the data from conn1 and conn2. - logFile := openLog(conn1.LocalAddr().String(), conn1.RemoteAddr().String(), conn2.LocalAddr().String(), conn2.RemoteAddr().String()) - if logFile != nil { - w := io.MultiWriter(conn1, logFile) - io.Copy(w, conn2) - } else { - io.Copy(conn1, conn2) - } - conn1.Close() - log.Println("[←]", "close the connect at local:["+conn1.LocalAddr().String()+"] and remote:["+conn1.RemoteAddr().String()+"]") - //conn2.Close() - //log.Println("[←]", "close the connect at local:["+conn2.LocalAddr().String()+"] and remote:["+conn2.RemoteAddr().String()+"]") - wg.Done() -} -func openLog(address1, address2, address3, address4 string) *os.File { - args := os.Args - argc := len(os.Args) - var logFileError error - var logFile *os.File - if argc > 5 && args[4] == "-log" { - address1 = strings.Replace(address1, ":", "_", -1) - address2 = strings.Replace(address2, ":", "_", -1) - address3 = strings.Replace(address3, ":", "_", -1) - address4 = strings.Replace(address4, ":", "_", -1) - timeStr := time.Now().Format("2006_01_02_15_04_05") // "2006-01-02 15:04:05" - logPath := args[5] + "/" + timeStr + args[1] + "-" + address1 + "_" + address2 + "-" + address3 + "_" + address4 + ".log" - logPath = strings.Replace(logPath, `\`, "/", -1) - logPath = strings.Replace(logPath, "//", "/", -1) - logFile, logFileError = os.OpenFile(logPath, os.O_APPEND|os.O_CREATE, 0666) - if logFileError != nil { - log.Fatalln("[x]", "log file path error.", logFileError.Error()) - } - log.Println("[√]", "open test log file success. path:", logPath) - } - return logFile -} diff --git a/src/mod/tcpprox/udpprox.go b/src/mod/tcpprox/udpprox.go deleted file mode 100644 index 553e85b..0000000 --- a/src/mod/tcpprox/udpprox.go +++ /dev/null @@ -1,89 +0,0 @@ -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 - } - } -} diff --git a/src/mod/utils/utils.go b/src/mod/utils/utils.go index 9af3ebc..1fe1699 100644 --- a/src/mod/utils/utils.go +++ b/src/mod/utils/utils.go @@ -68,9 +68,9 @@ func PostBool(r *http.Request, key string) (bool, error) { x = strings.TrimSpace(x) - if x == "1" || strings.ToLower(x) == "true" { + if x == "1" || strings.ToLower(x) == "true" || strings.ToLower(x) == "on" { return true, nil - } else if x == "0" || strings.ToLower(x) == "false" { + } else if x == "0" || strings.ToLower(x) == "false" || strings.ToLower(x) == "off" { return false, nil } diff --git a/src/start.go b/src/start.go index acf3106..f7120bd 100644 --- a/src/start.go +++ b/src/start.go @@ -23,7 +23,7 @@ import ( "imuslab.com/zoraxy/mod/sshprox" "imuslab.com/zoraxy/mod/statistic" "imuslab.com/zoraxy/mod/statistic/analytic" - "imuslab.com/zoraxy/mod/tcpprox" + "imuslab.com/zoraxy/mod/streamproxy" "imuslab.com/zoraxy/mod/tlscert" "imuslab.com/zoraxy/mod/webserv" ) @@ -229,7 +229,7 @@ func startupSequence() { webSshManager = sshprox.NewSSHProxyManager() //Create TCP Proxy Manager - tcpProxyManager = tcpprox.NewTCProxy(&tcpprox.Options{ + streamProxyManager = streamproxy.NewStreamProxy(&streamproxy.Options{ Database: sysdb, AccessControlHandler: accessController.DefaultAccessRule.AllowConnectionAccess, }) diff --git a/src/web/components/access.html b/src/web/components/access.html index c1bafb7..bb06e1d 100644 --- a/src/web/components/access.html +++ b/src/web/components/access.html @@ -65,7 +65,7 @@
-