mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
![Arko Dasgupta](/assets/img/avatar_default.png)
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>
98 lines
2.5 KiB
Go
98 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"sync"
|
|
|
|
"github.com/ishidawataru/sctp"
|
|
)
|
|
|
|
// SCTPProxy is a proxy for SCTP connections. It implements the Proxy interface to
|
|
// handle SCTP traffic forwarding between the frontend and backend addresses.
|
|
type SCTPProxy struct {
|
|
listener *sctp.SCTPListener
|
|
frontendAddr *sctp.SCTPAddr
|
|
backendAddr *sctp.SCTPAddr
|
|
}
|
|
|
|
// NewSCTPProxy creates a new SCTPProxy.
|
|
func NewSCTPProxy(frontendAddr, backendAddr *sctp.SCTPAddr) (*SCTPProxy, error) {
|
|
// detect version of hostIP to bind only to correct version
|
|
ipVersion := ipv4
|
|
if frontendAddr.IPAddrs[0].IP.To4() == nil {
|
|
ipVersion = ipv6
|
|
}
|
|
listener, err := sctp.ListenSCTP("sctp"+string(ipVersion), frontendAddr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// If the port in frontendAddr was 0 then ListenSCTP will have a picked
|
|
// a port to listen on, hence the call to Addr to get that actual port:
|
|
return &SCTPProxy{
|
|
listener: listener,
|
|
frontendAddr: listener.Addr().(*sctp.SCTPAddr),
|
|
backendAddr: backendAddr,
|
|
}, nil
|
|
}
|
|
|
|
func (proxy *SCTPProxy) clientLoop(client *sctp.SCTPConn, quit chan bool) {
|
|
backend, err := sctp.DialSCTP("sctp", nil, proxy.backendAddr)
|
|
if err != nil {
|
|
log.Printf("Can't forward traffic to backend sctp/%v: %s\n", proxy.backendAddr, err)
|
|
client.Close()
|
|
return
|
|
}
|
|
clientC := sctp.NewSCTPSndRcvInfoWrappedConn(client)
|
|
backendC := sctp.NewSCTPSndRcvInfoWrappedConn(backend)
|
|
|
|
var wg sync.WaitGroup
|
|
var broker = func(to, from net.Conn) {
|
|
io.Copy(to, from)
|
|
from.Close()
|
|
to.Close()
|
|
wg.Done()
|
|
}
|
|
|
|
wg.Add(2)
|
|
go broker(clientC, backendC)
|
|
go broker(backendC, clientC)
|
|
|
|
finish := make(chan struct{})
|
|
go func() {
|
|
wg.Wait()
|
|
close(finish)
|
|
}()
|
|
|
|
select {
|
|
case <-quit:
|
|
case <-finish:
|
|
}
|
|
clientC.Close()
|
|
backendC.Close()
|
|
<-finish
|
|
}
|
|
|
|
// Run starts forwarding the traffic using SCTP.
|
|
func (proxy *SCTPProxy) Run() {
|
|
quit := make(chan bool)
|
|
defer close(quit)
|
|
for {
|
|
client, err := proxy.listener.Accept()
|
|
if err != nil {
|
|
log.Printf("Stopping proxy on sctp/%v for sctp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
|
|
return
|
|
}
|
|
go proxy.clientLoop(client.(*sctp.SCTPConn), quit)
|
|
}
|
|
}
|
|
|
|
// Close stops forwarding the traffic.
|
|
func (proxy *SCTPProxy) Close() { proxy.listener.Close() }
|
|
|
|
// FrontendAddr returns the SCTP address on which the proxy is listening.
|
|
func (proxy *SCTPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
|
|
|
// BackendAddr returns the SCTP proxied address.
|
|
func (proxy *SCTPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|