mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
33a82a26a8
1. Allocate either a IPv4 and/or IPv6 Port Binding (HostIP, HostPort, ContainerIP, ContainerPort) based on the input and system parameters 2. Update the userland proxy as well as dummy proxy (inside port mapper) to specifically listen on either the IPv4 or IPv6 network Signed-off-by: Arko Dasgupta <arko.dasgupta@docker.com>
94 lines
2.3 KiB
Go
94 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"sync"
|
|
)
|
|
|
|
// 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.TCPListener
|
|
frontendAddr *net.TCPAddr
|
|
backendAddr *net.TCPAddr
|
|
}
|
|
|
|
// NewTCPProxy creates a new TCPProxy.
|
|
func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) {
|
|
// detect version of hostIP to bind only to correct version
|
|
ipVersion := ipv4
|
|
if frontendAddr.IP.To4() == nil {
|
|
ipVersion = ipv6
|
|
}
|
|
listener, err := net.ListenTCP("tcp"+string(ipVersion), frontendAddr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// 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().(*net.TCPAddr),
|
|
backendAddr: backendAddr,
|
|
}, nil
|
|
}
|
|
|
|
func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
|
|
backend, err := net.DialTCP("tcp", nil, proxy.backendAddr)
|
|
if err != nil {
|
|
log.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err)
|
|
client.Close()
|
|
return
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
var broker = func(to, from *net.TCPConn) {
|
|
io.Copy(to, from)
|
|
from.CloseRead()
|
|
to.CloseWrite()
|
|
wg.Done()
|
|
}
|
|
|
|
wg.Add(2)
|
|
go broker(client, backend)
|
|
go broker(backend, client)
|
|
|
|
finish := make(chan struct{})
|
|
go func() {
|
|
wg.Wait()
|
|
close(finish)
|
|
}()
|
|
|
|
select {
|
|
case <-quit:
|
|
case <-finish:
|
|
}
|
|
client.Close()
|
|
backend.Close()
|
|
<-finish
|
|
}
|
|
|
|
// 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 {
|
|
log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
|
|
return
|
|
}
|
|
go proxy.clientLoop(client.(*net.TCPConn), 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 }
|