Files
linuxkit/alpine/packages/proxy/libproxy/tcp_proxy.go
2016-06-10 16:05:14 +01:00

106 lines
2.5 KiB
Go

package libproxy
import (
"io"
"net"
"github.com/Sirupsen/logrus"
)
type Conn interface {
io.Reader
io.Writer
io.Closer
CloseRead() error
CloseWrite() error
}
// TCPProxy is a proxy for TCP connections. It implements the Proxy interface to
// handle TCP traffic forwarding between the frontend and backend addresses.
type TCPProxy struct {
listener net.Listener
frontendAddr net.Addr
backendAddr *net.TCPAddr
}
// NewTCPProxy creates a new TCPProxy.
func NewTCPProxy(listener net.Listener, backendAddr *net.TCPAddr) (*TCPProxy, error) {
// If the port in frontendAddr was 0 then ListenTCP will have a picked
// a port to listen on, hence the call to Addr to get that actual port:
return &TCPProxy{
listener: listener,
frontendAddr: listener.Addr(),
backendAddr: backendAddr,
}, nil
}
func HandleTCPConnection(client Conn, backendAddr *net.TCPAddr, quit chan bool) {
backend, err := net.DialTCP("tcp", nil, backendAddr)
if err != nil {
logrus.Printf("Can't forward traffic to backend tcp/%v: %s\n", backendAddr, err)
client.Close()
return
}
event := make(chan int64)
var broker = func(to, from Conn) {
written, err := io.Copy(to, from)
if err != nil {
logrus.Println("error copying:", err)
}
err = from.CloseRead()
if err != nil {
logrus.Println("error CloseRead from:", err)
}
err = to.CloseWrite()
if err != nil {
logrus.Println("error CloseWrite to:", err)
}
event <- written
}
go broker(client, backend)
go broker(backend, client)
var transferred int64
for i := 0; i < 2; i++ {
select {
case written := <-event:
transferred += written
case <-quit:
// Interrupt the two brokers and "join" them.
client.Close()
backend.Close()
for ; i < 2; i++ {
transferred += <-event
}
return
}
}
client.Close()
backend.Close()
}
// Run starts forwarding the traffic using TCP.
func (proxy *TCPProxy) Run() {
quit := make(chan bool)
defer close(quit)
for {
client, err := proxy.listener.Accept()
if err != nil {
logrus.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
return
}
go HandleTCPConnection(client.(Conn), proxy.backendAddr, quit)
}
}
// Close stops forwarding the traffic.
func (proxy *TCPProxy) Close() { proxy.listener.Close() }
// FrontendAddr returns the TCP address on which the proxy is listening.
func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
// BackendAddr returns the TCP proxied address.
func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }