github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/cmd/proxy/sctp_proxy.go (about) 1 package main 2 3 import ( 4 "io" 5 "log" 6 "net" 7 "sync" 8 9 "github.com/ishidawataru/sctp" 10 ) 11 12 // SCTPProxy is a proxy for SCTP connections. It implements the Proxy interface to 13 // handle SCTP traffic forwarding between the frontend and backend addresses. 14 type SCTPProxy struct { 15 listener *sctp.SCTPListener 16 frontendAddr *sctp.SCTPAddr 17 backendAddr *sctp.SCTPAddr 18 } 19 20 // NewSCTPProxy creates a new SCTPProxy. 21 func NewSCTPProxy(frontendAddr, backendAddr *sctp.SCTPAddr) (*SCTPProxy, error) { 22 // detect version of hostIP to bind only to correct version 23 ipVersion := ipv4 24 if frontendAddr.IPAddrs[0].IP.To4() == nil { 25 ipVersion = ipv6 26 } 27 listener, err := sctp.ListenSCTP("sctp"+string(ipVersion), frontendAddr) 28 if err != nil { 29 return nil, err 30 } 31 // If the port in frontendAddr was 0 then ListenSCTP will have a picked 32 // a port to listen on, hence the call to Addr to get that actual port: 33 return &SCTPProxy{ 34 listener: listener, 35 frontendAddr: listener.Addr().(*sctp.SCTPAddr), 36 backendAddr: backendAddr, 37 }, nil 38 } 39 40 func (proxy *SCTPProxy) clientLoop(client *sctp.SCTPConn, quit chan bool) { 41 backend, err := sctp.DialSCTP("sctp", nil, proxy.backendAddr) 42 if err != nil { 43 log.Printf("Can't forward traffic to backend sctp/%v: %s\n", proxy.backendAddr, err) 44 client.Close() 45 return 46 } 47 clientC := sctp.NewSCTPSndRcvInfoWrappedConn(client) 48 backendC := sctp.NewSCTPSndRcvInfoWrappedConn(backend) 49 50 var wg sync.WaitGroup 51 var broker = func(to, from net.Conn) { 52 io.Copy(to, from) 53 from.Close() 54 to.Close() 55 wg.Done() 56 } 57 58 wg.Add(2) 59 go broker(clientC, backendC) 60 go broker(backendC, clientC) 61 62 finish := make(chan struct{}) 63 go func() { 64 wg.Wait() 65 close(finish) 66 }() 67 68 select { 69 case <-quit: 70 case <-finish: 71 } 72 clientC.Close() 73 backendC.Close() 74 <-finish 75 } 76 77 // Run starts forwarding the traffic using SCTP. 78 func (proxy *SCTPProxy) Run() { 79 quit := make(chan bool) 80 defer close(quit) 81 for { 82 client, err := proxy.listener.Accept() 83 if err != nil { 84 log.Printf("Stopping proxy on sctp/%v for sctp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) 85 return 86 } 87 go proxy.clientLoop(client.(*sctp.SCTPConn), quit) 88 } 89 } 90 91 // Close stops forwarding the traffic. 92 func (proxy *SCTPProxy) Close() { proxy.listener.Close() } 93 94 // FrontendAddr returns the SCTP address on which the proxy is listening. 95 func (proxy *SCTPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr } 96 97 // BackendAddr returns the SCTP proxied address. 98 func (proxy *SCTPProxy) BackendAddr() net.Addr { return proxy.backendAddr }