1
0

tcpprox.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package streamproxy
  2. import (
  3. "errors"
  4. "io"
  5. "log"
  6. "net"
  7. "strconv"
  8. "strings"
  9. "sync"
  10. "sync/atomic"
  11. "time"
  12. )
  13. func isValidIP(ip string) bool {
  14. parsedIP := net.ParseIP(ip)
  15. return parsedIP != nil
  16. }
  17. func isValidPort(port string) bool {
  18. portInt, err := strconv.Atoi(port)
  19. if err != nil {
  20. return false
  21. }
  22. if portInt < 1 || portInt > 65535 {
  23. return false
  24. }
  25. return true
  26. }
  27. func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup, accumulator *atomic.Int64) {
  28. n, err := io.Copy(conn1, conn2)
  29. if err != nil {
  30. return
  31. }
  32. accumulator.Add(n) //Add to accumulator
  33. conn1.Close()
  34. log.Println("[←]", "close the connect at local:["+conn1.LocalAddr().String()+"] and remote:["+conn1.RemoteAddr().String()+"]")
  35. //conn2.Close()
  36. //log.Println("[←]", "close the connect at local:["+conn2.LocalAddr().String()+"] and remote:["+conn2.RemoteAddr().String()+"]")
  37. wg.Done()
  38. }
  39. func forward(conn1 net.Conn, conn2 net.Conn, aTob *atomic.Int64, bToa *atomic.Int64) {
  40. log.Printf("[+] start transmit. [%s],[%s] <-> [%s],[%s] \n", conn1.LocalAddr().String(), conn1.RemoteAddr().String(), conn2.LocalAddr().String(), conn2.RemoteAddr().String())
  41. var wg sync.WaitGroup
  42. // wait tow goroutines
  43. wg.Add(2)
  44. go connCopy(conn1, conn2, &wg, aTob)
  45. go connCopy(conn2, conn1, &wg, bToa)
  46. //blocking when the wg is locked
  47. wg.Wait()
  48. }
  49. func (c *ProxyRelayConfig) accept(listener net.Listener) (net.Conn, error) {
  50. conn, err := listener.Accept()
  51. if err != nil {
  52. return nil, err
  53. }
  54. //Check if connection in blacklist or whitelist
  55. if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok {
  56. if !c.parent.Options.AccessControlHandler(conn) {
  57. time.Sleep(300 * time.Millisecond)
  58. conn.Close()
  59. log.Println("[x]", "Connection from "+addr.IP.String()+" rejected by access control policy")
  60. return nil, errors.New("Connection from " + addr.IP.String() + " rejected by access control policy")
  61. }
  62. }
  63. log.Println("[√]", "accept a new client. remote address:["+conn.RemoteAddr().String()+"], local address:["+conn.LocalAddr().String()+"]")
  64. return conn, err
  65. }
  66. func startListener(address string) (net.Listener, error) {
  67. log.Println("[+]", "try to start server on:["+address+"]")
  68. server, err := net.Listen("tcp", address)
  69. if err != nil {
  70. return nil, errors.New("listen address [" + address + "] faild")
  71. }
  72. log.Println("[√]", "start listen at address:["+address+"]")
  73. return server, nil
  74. }
  75. /*
  76. Forwarder Functions
  77. */
  78. /*
  79. portA -> server
  80. server -> portB
  81. */
  82. func (c *ProxyRelayConfig) Port2host(allowPort string, targetAddress string, stopChan chan bool) error {
  83. listenerStartingAddr := allowPort
  84. if isValidPort(allowPort) {
  85. //number only, e.g. 8080
  86. listenerStartingAddr = "0.0.0.0:" + allowPort
  87. } else if strings.HasPrefix(allowPort, ":") && isValidPort(allowPort[1:]) {
  88. //port number starting with :, e.g. :8080
  89. listenerStartingAddr = "0.0.0.0" + allowPort
  90. }
  91. server, err := startListener(listenerStartingAddr)
  92. if err != nil {
  93. return err
  94. }
  95. targetAddress = strings.TrimSpace(targetAddress)
  96. //Start stop handler
  97. go func() {
  98. <-stopChan
  99. log.Println("[x]", "Received stop signal. Exiting Port to Host forwarder")
  100. server.Close()
  101. }()
  102. //Start blocking loop for accepting connections
  103. for {
  104. conn, err := c.accept(server)
  105. if err != nil {
  106. if errors.Is(err, net.ErrClosed) {
  107. //Terminate by stop chan. Exit listener loop
  108. return nil
  109. }
  110. //Connection error. Retry
  111. continue
  112. }
  113. go func(targetAddress string) {
  114. log.Println("[+]", "start connect host:["+targetAddress+"]")
  115. target, err := net.Dial("tcp", targetAddress)
  116. if err != nil {
  117. // temporarily unavailable, don't use fatal.
  118. log.Println("[x]", "connect target address ["+targetAddress+"] faild. retry in ", c.Timeout, "seconds. ")
  119. conn.Close()
  120. log.Println("[←]", "close the connect at local:["+conn.LocalAddr().String()+"] and remote:["+conn.RemoteAddr().String()+"]")
  121. time.Sleep(time.Duration(c.Timeout) * time.Second)
  122. return
  123. }
  124. log.Println("[→]", "connect target address ["+targetAddress+"] success.")
  125. forward(target, conn, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer)
  126. }(targetAddress)
  127. }
  128. }