tcp_proxy.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package main
  2. import (
  3. "io"
  4. "log"
  5. "net"
  6. "sync"
  7. )
  8. // TCPProxy is a proxy for TCP connections. It implements the Proxy interface to
  9. // handle TCP traffic forwarding between the frontend and backend addresses.
  10. type TCPProxy struct {
  11. listener *net.TCPListener
  12. frontendAddr *net.TCPAddr
  13. backendAddr *net.TCPAddr
  14. }
  15. // NewTCPProxy creates a new TCPProxy.
  16. func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) {
  17. listener, err := net.ListenTCP("tcp", frontendAddr)
  18. if err != nil {
  19. return nil, err
  20. }
  21. // If the port in frontendAddr was 0 then ListenTCP will have a picked
  22. // a port to listen on, hence the call to Addr to get that actual port:
  23. return &TCPProxy{
  24. listener: listener,
  25. frontendAddr: listener.Addr().(*net.TCPAddr),
  26. backendAddr: backendAddr,
  27. }, nil
  28. }
  29. func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
  30. backend, err := net.DialTCP("tcp", nil, proxy.backendAddr)
  31. if err != nil {
  32. log.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err)
  33. client.Close()
  34. return
  35. }
  36. var wg sync.WaitGroup
  37. var broker = func(to, from *net.TCPConn) {
  38. io.Copy(to, from)
  39. from.CloseRead()
  40. to.CloseWrite()
  41. wg.Done()
  42. }
  43. wg.Add(2)
  44. go broker(client, backend)
  45. go broker(backend, client)
  46. finish := make(chan struct{})
  47. go func() {
  48. wg.Wait()
  49. close(finish)
  50. }()
  51. select {
  52. case <-quit:
  53. case <-finish:
  54. }
  55. client.Close()
  56. backend.Close()
  57. <-finish
  58. }
  59. // Run starts forwarding the traffic using TCP.
  60. func (proxy *TCPProxy) Run() {
  61. quit := make(chan bool)
  62. defer close(quit)
  63. for {
  64. client, err := proxy.listener.Accept()
  65. if err != nil {
  66. log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
  67. return
  68. }
  69. go proxy.clientLoop(client.(*net.TCPConn), quit)
  70. }
  71. }
  72. // Close stops forwarding the traffic.
  73. func (proxy *TCPProxy) Close() { proxy.listener.Close() }
  74. // FrontendAddr returns the TCP address on which the proxy is listening.
  75. func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
  76. // BackendAddr returns the TCP proxied address.
  77. func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }