udpprox.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package tcpprox
  2. import (
  3. "errors"
  4. "log"
  5. "net"
  6. "time"
  7. )
  8. /*
  9. UDP Proxy Module
  10. */
  11. // Information maintained for each client/server connection
  12. type udpClientServerConn struct {
  13. ClientAddr *net.UDPAddr // Address of the client
  14. ServerConn *net.UDPConn // UDP connection to server
  15. }
  16. // Generate a new connection by opening a UDP connection to the server
  17. func createNewUDPConn(srvAddr, cliAddr *net.UDPAddr) *udpClientServerConn {
  18. conn := new(udpClientServerConn)
  19. conn.ClientAddr = cliAddr
  20. srvudp, err := net.DialUDP("udp", nil, srvAddr)
  21. if err != nil {
  22. return nil
  23. }
  24. conn.ServerConn = srvudp
  25. return conn
  26. }
  27. // Start listener, return inbound lisener and proxy target UDP address
  28. func initUDPConnections(listenAddr string, targetAddress string) (*net.UDPConn, *net.UDPAddr, error) {
  29. // Set up Proxy
  30. saddr, err := net.ResolveUDPAddr("udp", listenAddr)
  31. if err != nil {
  32. return nil, nil, err
  33. }
  34. inboundConn, err := net.ListenUDP("udp", saddr)
  35. if err != nil {
  36. return nil, nil, err
  37. }
  38. log.Println("[UDP] Proxy listening on " + listenAddr)
  39. outboundConn, err := net.ResolveUDPAddr("udp", targetAddress)
  40. if err != nil {
  41. return nil, nil, err
  42. }
  43. return inboundConn, outboundConn, nil
  44. }
  45. // Go routine which manages connection from server to single client
  46. func (c *ProxyRelayConfig) RunUDPConnectionRelay(conn *udpClientServerConn, lisenter *net.UDPConn) {
  47. var buffer [1500]byte
  48. for {
  49. // Read from server
  50. n, err := conn.ServerConn.Read(buffer[0:])
  51. if err != nil {
  52. if errors.Is(err, net.ErrClosed) {
  53. return
  54. }
  55. continue
  56. }
  57. // Relay it to client
  58. _, err = lisenter.WriteToUDP(buffer[0:n], conn.ClientAddr)
  59. if err != nil {
  60. continue
  61. }
  62. }
  63. }
  64. // Close all connections that waiting for read from server
  65. func (c *ProxyRelayConfig) CloseAllUDPConnections() {
  66. c.udpClientMap.Range(func(clientAddr, clientServerConn interface{}) bool {
  67. conn := clientServerConn.(*udpClientServerConn)
  68. conn.ServerConn.Close()
  69. return true
  70. })
  71. }
  72. func (c *ProxyRelayConfig) ForwardUDP(address1, address2 string, stopChan chan bool) error {
  73. //By default the incoming listen Address is int
  74. //We need to add the loopback address into it
  75. address1 = "127.0.0.1:" + address1
  76. lisener, targetAddr, err := initUDPConnections(address1, address2)
  77. if err != nil {
  78. return err
  79. }
  80. go func() {
  81. //Stop channel receiver
  82. for {
  83. select {
  84. case <-stopChan:
  85. //Stop signal received
  86. //Stop server -> client forwarder
  87. c.CloseAllUDPConnections()
  88. //Stop client -> server forwarder
  89. //Force close, will terminate ReadFromUDP for inbound listener
  90. lisener.Close()
  91. return
  92. default:
  93. time.Sleep(100 * time.Millisecond)
  94. }
  95. }
  96. }()
  97. var buffer [1500]byte
  98. for {
  99. n, cliaddr, err := lisener.ReadFromUDP(buffer[0:])
  100. if err != nil {
  101. if errors.Is(err, net.ErrClosed) {
  102. //Proxy stopped
  103. return nil
  104. }
  105. continue
  106. }
  107. c.aTobAccumulatedByteTransfer.Add(int64(n))
  108. saddr := cliaddr.String()
  109. rawConn, found := c.udpClientMap.Load(saddr)
  110. var conn *udpClientServerConn
  111. if !found {
  112. conn = createNewUDPConn(targetAddr, cliaddr)
  113. if conn == nil {
  114. continue
  115. }
  116. c.udpClientMap.Store(saddr, conn)
  117. log.Println("[UDP] Created new connection for client " + saddr)
  118. // Fire up routine to manage new connection
  119. go c.RunUDPConnectionRelay(conn, lisener)
  120. } else {
  121. log.Println("[UDP] Found connection for client " + saddr)
  122. conn = rawConn.(*udpClientServerConn)
  123. }
  124. // Relay to server
  125. _, err = conn.ServerConn.Write(buffer[0:n])
  126. if err != nil {
  127. continue
  128. }
  129. }
  130. }