Bladeren bron

Update sctp package

This commit updates the vendored ishidawataru/sctp and adapts its used
types.

Signed-off-by: Sascha Grunert <sgrunert@suse.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sascha Grunert 6 jaren geleden
bovenliggende
commit
c5c8653912

+ 2 - 2
libnetwork/cmd/proxy/main.go

@@ -51,8 +51,8 @@ func parseHostContainerAddrs() (host net.Addr, container net.Addr) {
 		host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
 		container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
 	case "sctp":
-		host = &sctp.SCTPAddr{IP: []net.IP{net.ParseIP(*hostIP)}, Port: *hostPort}
-		container = &sctp.SCTPAddr{IP: []net.IP{net.ParseIP(*containerIP)}, Port: *containerPort}
+		host = &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: net.ParseIP(*hostIP)}}, Port: *hostPort}
+		container = &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: net.ParseIP(*containerIP)}}, Port: *containerPort}
 	default:
 		log.Fatalf("unsupported protocol %s", *proto)
 	}

+ 2 - 2
libnetwork/cmd/proxy/network_proxy_test.go

@@ -285,7 +285,7 @@ func TestSCTP4Proxy(t *testing.T) {
 	backend := NewEchoServer(t, "sctp", "127.0.0.1:0", EchoServerOptions{})
 	defer backend.Close()
 	backend.Run()
-	frontendAddr := &sctp.SCTPAddr{IP: []net.IP{net.IPv4(127, 0, 0, 1)}, Port: 0}
+	frontendAddr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: net.IPv4(127, 0, 0, 1)}}, Port: 0}
 	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
 	if err != nil {
 		t.Fatal(err)
@@ -298,7 +298,7 @@ func TestSCTP6Proxy(t *testing.T) {
 	backend := NewEchoServer(t, "sctp", "[::1]:0", EchoServerOptions{})
 	defer backend.Close()
 	backend.Run()
-	frontendAddr := &sctp.SCTPAddr{IP: []net.IP{net.IPv6loopback}, Port: 0}
+	frontendAddr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: net.IPv6loopback}}, Port: 0}
 	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
 	if err != nil {
 		t.Fatal(err)

+ 9 - 9
libnetwork/portmapper/mapper.go

@@ -115,16 +115,16 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
 
 		m = &mapping{
 			proto:     proto,
-			host:      &sctp.SCTPAddr{IP: []net.IP{hostIP}, Port: allocatedHostPort},
+			host:      &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: hostIP}}, Port: allocatedHostPort},
 			container: container,
 		}
 
 		if useProxy {
 			sctpAddr := container.(*sctp.SCTPAddr)
-			if len(sctpAddr.IP) == 0 {
+			if len(sctpAddr.IPAddrs) == 0 {
 				return nil, ErrSCTPAddrNoIP
 			}
-			m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, sctpAddr.IP[0], sctpAddr.Port, pm.proxyPath)
+			m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, sctpAddr.IPAddrs[0].IP, sctpAddr.Port, pm.proxyPath)
 			if err != nil {
 				return nil, err
 			}
@@ -210,10 +210,10 @@ func (pm *PortMapper) Unmap(host net.Addr) error {
 	case *net.UDPAddr:
 		return pm.Allocator.ReleasePort(a.IP, "udp", a.Port)
 	case *sctp.SCTPAddr:
-		if len(a.IP) == 0 {
+		if len(a.IPAddrs) == 0 {
 			return ErrSCTPAddrNoIP
 		}
-		return pm.Allocator.ReleasePort(a.IP[0], "sctp", a.Port)
+		return pm.Allocator.ReleasePort(a.IPAddrs[0].IP, "sctp", a.Port)
 	}
 	return ErrUnknownBackendAddressType
 }
@@ -239,11 +239,11 @@ func getKey(a net.Addr) string {
 	case *net.UDPAddr:
 		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
 	case *sctp.SCTPAddr:
-		if len(t.IP) == 0 {
+		if len(t.IPAddrs) == 0 {
 			logrus.Error(ErrSCTPAddrNoIP)
 			return ""
 		}
-		return fmt.Sprintf("%s:%d/%s", t.IP[0].String(), t.Port, "sctp")
+		return fmt.Sprintf("%s:%d/%s", t.IPAddrs[0].IP.String(), t.Port, "sctp")
 	}
 	return ""
 }
@@ -255,11 +255,11 @@ func getIPAndPort(a net.Addr) (net.IP, int) {
 	case *net.UDPAddr:
 		return t.IP, t.Port
 	case *sctp.SCTPAddr:
-		if len(t.IP) == 0 {
+		if len(t.IPAddrs) == 0 {
 			logrus.Error(ErrSCTPAddrNoIP)
 			return nil, 0
 		}
-		return t.IP[0], t.Port
+		return t.IPAddrs[0].IP, t.Port
 	}
 	return nil, 0
 }

+ 1 - 1
libnetwork/portmapper/proxy.go

@@ -90,7 +90,7 @@ func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, er
 		addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
 		return &dummyProxy{addr: addr}, nil
 	case "sctp":
-		addr := &sctp.SCTPAddr{IP: []net.IP{hostIP}, Port: hostPort}
+		addr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: hostIP}}, Port: hostPort}
 		return &dummyProxy{addr: addr}, nil
 	default:
 		return nil, fmt.Errorf("Unknown addr type: %s", proto)

+ 2 - 2
libnetwork/types/types.go

@@ -99,7 +99,7 @@ func (p PortBinding) HostAddr() (net.Addr, error) {
 	case TCP:
 		return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
 	case SCTP:
-		return &sctp.SCTPAddr{IP: []net.IP{p.HostIP}, Port: int(p.HostPort)}, nil
+		return &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: p.HostIP}}, Port: int(p.HostPort)}, nil
 	default:
 		return nil, ErrInvalidProtocolBinding(p.Proto.String())
 	}
@@ -113,7 +113,7 @@ func (p PortBinding) ContainerAddr() (net.Addr, error) {
 	case TCP:
 		return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
 	case SCTP:
-		return &sctp.SCTPAddr{IP: []net.IP{p.IP}, Port: int(p.Port)}, nil
+		return &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: p.IP}}, Port: int(p.Port)}, nil
 	default:
 		return nil, ErrInvalidProtocolBinding(p.Proto.String())
 	}

+ 1 - 1
libnetwork/vendor.conf

@@ -48,7 +48,7 @@ golang.org/x/net                        a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1
 golang.org/x/sys                        d455e41777fca6e8a5a79e34a14b8368bc11d9ba
 golang.org/x/sync                       1d60e4601c6fd243af51cc01ddf169918a5407ca
 github.com/pkg/errors                   ba968bfe8b2f7e042a574c888954fccecfa385b4 # v0.8.1
-github.com/ishidawataru/sctp            07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
+github.com/ishidawataru/sctp            6e2cb1366111dcf547c13531e3a263a067715847
 
 gotest.tools                            b6e20af1ed078cd01a6413b734051a292450b4cb # v2.1.0
 github.com/google/go-cmp                3af367b6b30c263d47e8895973edcca9a49cf029 # v0.2.0

+ 27 - 0
libnetwork/vendor/github.com/ishidawataru/sctp/GO_LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 218 - 0
libnetwork/vendor/github.com/ishidawataru/sctp/ipsock_linux.go

@@ -0,0 +1,218 @@
+package sctp
+
+import (
+	"net"
+	"os"
+	"sync"
+	"syscall"
+)
+
+//from https://github.com/golang/go
+// Boolean to int.
+func boolint(b bool) int {
+	if b {
+		return 1
+	}
+	return 0
+}
+
+//from https://github.com/golang/go
+func ipToSockaddr(family int, ip net.IP, port int, zone string) (syscall.Sockaddr, error) {
+	switch family {
+	case syscall.AF_INET:
+		if len(ip) == 0 {
+			ip = net.IPv4zero
+		}
+		ip4 := ip.To4()
+		if ip4 == nil {
+			return nil, &net.AddrError{Err: "non-IPv4 address", Addr: ip.String()}
+		}
+		sa := &syscall.SockaddrInet4{Port: port}
+		copy(sa.Addr[:], ip4)
+		return sa, nil
+	case syscall.AF_INET6:
+		// In general, an IP wildcard address, which is either
+		// "0.0.0.0" or "::", means the entire IP addressing
+		// space. For some historical reason, it is used to
+		// specify "any available address" on some operations
+		// of IP node.
+		//
+		// When the IP node supports IPv4-mapped IPv6 address,
+		// we allow an listener to listen to the wildcard
+		// address of both IP addressing spaces by specifying
+		// IPv6 wildcard address.
+		if len(ip) == 0 || ip.Equal(net.IPv4zero) {
+			ip = net.IPv6zero
+		}
+		// We accept any IPv6 address including IPv4-mapped
+		// IPv6 address.
+		ip6 := ip.To16()
+		if ip6 == nil {
+			return nil, &net.AddrError{Err: "non-IPv6 address", Addr: ip.String()}
+		}
+		//we set ZoneId to 0, as currently we use this functon only to probe the IP capabilities of the host
+		//if real Zone handling is required, the zone cache implementation in golang/net should be pulled here
+		sa := &syscall.SockaddrInet6{Port: port, ZoneId: 0}
+		copy(sa.Addr[:], ip6)
+		return sa, nil
+	}
+	return nil, &net.AddrError{Err: "invalid address family", Addr: ip.String()}
+}
+
+//from https://github.com/golang/go
+func sockaddr(a *net.TCPAddr, family int) (syscall.Sockaddr, error) {
+	if a == nil {
+		return nil, nil
+	}
+	return ipToSockaddr(family, a.IP, a.Port, a.Zone)
+}
+
+//from https://github.com/golang/go
+type ipStackCapabilities struct {
+	sync.Once             // guards following
+	ipv4Enabled           bool
+	ipv6Enabled           bool
+	ipv4MappedIPv6Enabled bool
+}
+
+//from https://github.com/golang/go
+var ipStackCaps ipStackCapabilities
+
+//from https://github.com/golang/go
+// supportsIPv4 reports whether the platform supports IPv4 networking
+// functionality.
+func supportsIPv4() bool {
+	ipStackCaps.Once.Do(ipStackCaps.probe)
+	return ipStackCaps.ipv4Enabled
+}
+
+//from https://github.com/golang/go
+// supportsIPv6 reports whether the platform supports IPv6 networking
+// functionality.
+func supportsIPv6() bool {
+	ipStackCaps.Once.Do(ipStackCaps.probe)
+	return ipStackCaps.ipv6Enabled
+}
+
+//from https://github.com/golang/go
+// supportsIPv4map reports whether the platform supports mapping an
+// IPv4 address inside an IPv6 address at transport layer
+// protocols. See RFC 4291, RFC 4038 and RFC 3493.
+func supportsIPv4map() bool {
+	ipStackCaps.Once.Do(ipStackCaps.probe)
+	return ipStackCaps.ipv4MappedIPv6Enabled
+}
+
+//from https://github.com/golang/go
+// Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
+// capabilities which are controlled by the IPV6_V6ONLY socket option
+// and kernel configuration.
+//
+// Should we try to use the IPv4 socket interface if we're only
+// dealing with IPv4 sockets? As long as the host system understands
+// IPv4-mapped IPv6, it's okay to pass IPv4-mapeed IPv6 addresses to
+// the IPv6 interface. That simplifies our code and is most
+// general. Unfortunately, we need to run on kernels built without
+// IPv6 support too. So probe the kernel to figure it out.
+func (p *ipStackCapabilities) probe() {
+	s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+	switch err {
+	case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
+	case nil:
+		syscall.Close(s)
+		p.ipv4Enabled = true
+	}
+	var probes = []struct {
+		laddr net.TCPAddr
+		value int
+	}{
+		// IPv6 communication capability
+		{laddr: net.TCPAddr{IP: net.IPv6loopback}, value: 1},
+		// IPv4-mapped IPv6 address communication capability
+		{laddr: net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)}, value: 0},
+	}
+
+	for i := range probes {
+		s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+		if err != nil {
+			continue
+		}
+		defer syscall.Close(s)
+		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
+		sa, err := sockaddr(&(probes[i].laddr), syscall.AF_INET6)
+		if err != nil {
+			continue
+		}
+		if err := syscall.Bind(s, sa); err != nil {
+			continue
+		}
+		if i == 0 {
+			p.ipv6Enabled = true
+		} else {
+			p.ipv4MappedIPv6Enabled = true
+		}
+	}
+}
+
+//from https://github.com/golang/go
+//Change: we check the first IP address in the list of candidate SCTP IP addresses
+func (a *SCTPAddr) isWildcard() bool {
+	if a == nil {
+		return true
+	}
+	if 0 == len(a.IPAddrs) {
+		return true
+	}
+
+	return a.IPAddrs[0].IP.IsUnspecified()
+}
+
+func (a *SCTPAddr) family() int {
+	if a != nil {
+		for _, ip := range a.IPAddrs {
+			if ip.IP.To4() == nil {
+				return syscall.AF_INET6
+			}
+		}
+	}
+	return syscall.AF_INET
+}
+
+//from https://github.com/golang/go
+func favoriteAddrFamily(network string, laddr *SCTPAddr, raddr *SCTPAddr, mode string) (family int, ipv6only bool) {
+	switch network[len(network)-1] {
+	case '4':
+		return syscall.AF_INET, false
+	case '6':
+		return syscall.AF_INET6, true
+	}
+
+	if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
+		if supportsIPv4map() || !supportsIPv4() {
+			return syscall.AF_INET6, false
+		}
+		if laddr == nil {
+			return syscall.AF_INET, false
+		}
+		return laddr.family(), false
+	}
+
+	if (laddr == nil || laddr.family() == syscall.AF_INET) &&
+		(raddr == nil || raddr.family() == syscall.AF_INET) {
+		return syscall.AF_INET, false
+	}
+	return syscall.AF_INET6, false
+}
+
+//from https://github.com/golang/go
+//Changes: it is for SCTP only
+func setDefaultSockopts(s int, family int, ipv6only bool) error {
+	if family == syscall.AF_INET6 {
+		// Allow both IP versions even if the OS default
+		// is otherwise. Note that some operating systems
+		// never admit this option.
+		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
+	}
+	// Allow broadcast.
+	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+}

+ 56 - 32
libnetwork/vendor/github.com/ishidawataru/sctp/sctp.go

@@ -197,37 +197,58 @@ func htons(h uint16) uint16 {
 
 var ntohs = htons
 
-func setNumOstreams(fd, num int) error {
-	param := InitMsg{
-		NumOstreams: uint16(num),
-	}
-	optlen := unsafe.Sizeof(param)
-	_, _, err := setsockopt(fd, SCTP_INITMSG, uintptr(unsafe.Pointer(&param)), uintptr(optlen))
+// setInitOpts sets options for an SCTP association initialization
+// see https://tools.ietf.org/html/rfc4960#page-25
+func setInitOpts(fd int, options InitMsg) error {
+	optlen := unsafe.Sizeof(options)
+	_, _, err := setsockopt(fd, SCTP_INITMSG, uintptr(unsafe.Pointer(&options)), uintptr(optlen))
 	return err
 }
 
+func setNumOstreams(fd, num int) error {
+	return setInitOpts(fd, InitMsg{NumOstreams: uint16(num)})
+}
+
 type SCTPAddr struct {
-	IP   []net.IP
-	Port int
+	IPAddrs []net.IPAddr
+	Port    int
 }
 
 func (a *SCTPAddr) ToRawSockAddrBuf() []byte {
-	buf := []byte{}
 	p := htons(uint16(a.Port))
-	for _, ip := range a.IP {
-		if ip.To4() != nil {
+	if len(a.IPAddrs) == 0 { // if a.IPAddrs list is empty - fall back to IPv4 zero addr
+		s := syscall.RawSockaddrInet4{
+			Family: syscall.AF_INET,
+			Port:   p,
+		}
+		copy(s.Addr[:], net.IPv4zero)
+		return toBuf(s)
+	}
+	buf := []byte{}
+	for _, ip := range a.IPAddrs {
+		ipBytes := ip.IP
+		if len(ipBytes) == 0 {
+			ipBytes = net.IPv4zero
+		}
+		if ip4 := ipBytes.To4(); ip4 != nil {
 			s := syscall.RawSockaddrInet4{
 				Family: syscall.AF_INET,
 				Port:   p,
 			}
-			copy(s.Addr[:], ip.To4())
+			copy(s.Addr[:], ip4)
 			buf = append(buf, toBuf(s)...)
 		} else {
+			var scopeid uint32
+			ifi, err := net.InterfaceByName(ip.Zone)
+			if err == nil {
+				scopeid = uint32(ifi.Index)
+			}
 			s := syscall.RawSockaddrInet6{
-				Family: syscall.AF_INET6,
-				Port:   p,
+				Family:   syscall.AF_INET6,
+				Port:     p,
+				Scope_id: scopeid,
 			}
-			copy(s.Addr[:], ip)
+			copy(s.Addr[:], ipBytes)
 			buf = append(buf, toBuf(s)...)
 		}
 	}
@@ -237,15 +258,15 @@ func (a *SCTPAddr) ToRawSockAddrBuf() []byte {
 func (a *SCTPAddr) String() string {
 	var b bytes.Buffer
 
-	for n, i := range a.IP {
-		if a.IP[n].To4() != nil {
+	for n, i := range a.IPAddrs {
+		if i.IP.To4() != nil {
 			b.WriteString(i.String())
-		} else if a.IP[n].To16() != nil {
+		} else if i.IP.To16() != nil {
 			b.WriteRune('[')
 			b.WriteString(i.String())
 			b.WriteRune(']')
 		}
-		if n < len(a.IP)-1 {
+		if n < len(a.IPAddrs)-1 {
 			b.WriteRune('/')
 		}
 	}
@@ -260,6 +281,7 @@ func ResolveSCTPAddr(network, addrs string) (*SCTPAddr, error) {
 	tcpnet := ""
 	switch network {
 	case "", "sctp":
+		tcpnet = "tcp"
 	case "sctp4":
 		tcpnet = "tcp4"
 	case "sctp6":
@@ -271,26 +293,26 @@ func ResolveSCTPAddr(network, addrs string) (*SCTPAddr, error) {
 	if len(elems) == 0 {
 		return nil, fmt.Errorf("invalid input: %s", addrs)
 	}
-	ipaddrs := make([]net.IP, 0, len(elems))
+	ipaddrs := make([]net.IPAddr, 0, len(elems))
 	for _, e := range elems[:len(elems)-1] {
 		tcpa, err := net.ResolveTCPAddr(tcpnet, e+":")
 		if err != nil {
 			return nil, err
 		}
-		ipaddrs = append(ipaddrs, tcpa.IP)
+		ipaddrs = append(ipaddrs, net.IPAddr{IP: tcpa.IP, Zone: tcpa.Zone})
 	}
 	tcpa, err := net.ResolveTCPAddr(tcpnet, elems[len(elems)-1])
 	if err != nil {
 		return nil, err
 	}
 	if tcpa.IP != nil {
-		ipaddrs = append(ipaddrs, tcpa.IP)
+		ipaddrs = append(ipaddrs, net.IPAddr{IP: tcpa.IP, Zone: tcpa.Zone})
 	} else {
 		ipaddrs = nil
 	}
 	return &SCTPAddr{
-		IP:   ipaddrs,
-		Port: tcpa.Port,
+		IPAddrs: ipaddrs,
+		Port:    tcpa.Port,
 	}, nil
 }
 
@@ -357,15 +379,12 @@ func (c *SCTPConn) Read(b []byte) (int, error) {
 }
 
 func (c *SCTPConn) SetInitMsg(numOstreams, maxInstreams, maxAttempts, maxInitTimeout int) error {
-	param := InitMsg{
+	return setInitOpts(c.fd(), InitMsg{
 		NumOstreams:    uint16(numOstreams),
 		MaxInstreams:   uint16(maxInstreams),
 		MaxAttempts:    uint16(maxAttempts),
 		MaxInitTimeout: uint16(maxInitTimeout),
-	}
-	optlen := unsafe.Sizeof(param)
-	_, _, err := setsockopt(c.fd(), SCTP_INITMSG, uintptr(unsafe.Pointer(&param)), uintptr(optlen))
-	return err
+	})
 }
 
 func (c *SCTPConn) SubscribeEvents(flags int) error {
@@ -473,7 +492,7 @@ func (c *SCTPConn) GetDefaultSentParam() (*SndRcvInfo, error) {
 
 func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
 	addr := &SCTPAddr{
-		IP: make([]net.IP, n),
+		IPAddrs: make([]net.IPAddr, n),
 	}
 
 	switch family := (*(*syscall.RawSockaddrAny)(ptr)).Addr.Family; family {
@@ -484,7 +503,7 @@ func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
 		for i := 0; i < n; i++ {
 			a := *(*syscall.RawSockaddrInet4)(unsafe.Pointer(
 				uintptr(ptr) + size*uintptr(i)))
-			addr.IP[i] = a.Addr[:]
+			addr.IPAddrs[i] = net.IPAddr{IP: a.Addr[:]}
 		}
 	case syscall.AF_INET6:
 		addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port)))
@@ -493,7 +512,12 @@ func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
 		for i := 0; i < n; i++ {
 			a := *(*syscall.RawSockaddrInet6)(unsafe.Pointer(
 				uintptr(ptr) + size*uintptr(i)))
-			addr.IP[i] = a.Addr[:]
+			var zone string
+			ifi, err := net.InterfaceByIndex(int(a.Scope_id))
+			if err == nil {
+				zone = ifi.Name
+			}
+			addr.IPAddrs[i] = net.IPAddr{IP: a.Addr[:], Zone: zone}
 		}
 	default:
 		return nil, fmt.Errorf("unknown address family: %d", family)

+ 60 - 51
libnetwork/vendor/github.com/ishidawataru/sctp/sctp_linux.go

@@ -3,7 +3,6 @@
 package sctp
 
 import (
-	"fmt"
 	"io"
 	"net"
 	"sync/atomic"
@@ -115,31 +114,14 @@ func (c *SCTPConn) Close() error {
 	return syscall.EBADF
 }
 
+// ListenSCTP - start listener on specified address/port
 func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
-	af := syscall.AF_INET
-	switch net {
-	case "sctp":
-		hasv6 := func(addr *SCTPAddr) bool {
-			if addr == nil {
-				return false
-			}
-			for _, ip := range addr.IP {
-				if ip.To4() == nil {
-					return true
-				}
-			}
-			return false
-		}
-		if hasv6(laddr) {
-			af = syscall.AF_INET6
-		}
-	case "sctp4":
-	case "sctp6":
-		af = syscall.AF_INET6
-	default:
-		return nil, fmt.Errorf("invalid net: %s", net)
-	}
+	return ListenSCTPExt(net, laddr, InitMsg{NumOstreams: SCTP_MAX_STREAM})
+}
 
+// ListenSCTPExt - start listener on specified address/port with given SCTP options
+func ListenSCTPExt(network string, laddr *SCTPAddr, options InitMsg) (*SCTPListener, error) {
+	af, ipv6only := favoriteAddrFamily(network, laddr, nil, "listen")
 	sock, err := syscall.Socket(
 		af,
 		syscall.SOCK_STREAM,
@@ -148,11 +130,30 @@ func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
 	if err != nil {
 		return nil, err
 	}
-	err = setNumOstreams(sock, SCTP_MAX_STREAM)
+
+	// close socket on error
+	defer func() {
+		if err != nil {
+			syscall.Close(sock)
+		}
+	}()
+	if err = setDefaultSockopts(sock, af, ipv6only); err != nil {
+		return nil, err
+	}
+	err = setInitOpts(sock, options)
 	if err != nil {
 		return nil, err
 	}
-	if laddr != nil && len(laddr.IP) != 0 {
+
+	if laddr != nil {
+		// If IP address and/or port was not provided so far, let's use the unspecified IPv4 or IPv6 address
+		if len(laddr.IPAddrs) == 0 {
+			if af == syscall.AF_INET {
+				laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv4zero})
+			} else if af == syscall.AF_INET6 {
+				laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv6zero})
+			}
+		}
 		err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
 		if err != nil {
 			return nil, err
@@ -167,40 +168,30 @@ func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
 	}, nil
 }
 
-func (ln *SCTPListener) Accept() (net.Conn, error) {
+// AcceptSCTP waits for and returns the next SCTP connection to the listener.
+func (ln *SCTPListener) AcceptSCTP() (*SCTPConn, error) {
 	fd, _, err := syscall.Accept4(ln.fd, 0)
 	return NewSCTPConn(fd, nil), err
 }
 
+// Accept waits for and returns the next connection connection to the listener.
+func (ln *SCTPListener) Accept() (net.Conn, error) {
+	return ln.AcceptSCTP()
+}
+
 func (ln *SCTPListener) Close() error {
 	syscall.Shutdown(ln.fd, syscall.SHUT_RDWR)
 	return syscall.Close(ln.fd)
 }
 
+// DialSCTP - bind socket to laddr (if given) and connect to raddr
 func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) {
-	af := syscall.AF_INET
-	switch net {
-	case "sctp":
-		hasv6 := func(addr *SCTPAddr) bool {
-			if addr == nil {
-				return false
-			}
-			for _, ip := range addr.IP {
-				if ip.To4() == nil {
-					return true
-				}
-			}
-			return false
-		}
-		if hasv6(laddr) || hasv6(raddr) {
-			af = syscall.AF_INET6
-		}
-	case "sctp4":
-	case "sctp6":
-		af = syscall.AF_INET6
-	default:
-		return nil, fmt.Errorf("invalid net: %s", net)
-	}
+	return DialSCTPExt(net, laddr, raddr, InitMsg{NumOstreams: SCTP_MAX_STREAM})
+}
+
+// DialSCTPExt - same as DialSCTP but with given SCTP options
+func DialSCTPExt(network string, laddr, raddr *SCTPAddr, options InitMsg) (*SCTPConn, error) {
+	af, ipv6only := favoriteAddrFamily(network, laddr, raddr, "dial")
 	sock, err := syscall.Socket(
 		af,
 		syscall.SOCK_STREAM,
@@ -209,11 +200,29 @@ func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) {
 	if err != nil {
 		return nil, err
 	}
-	err = setNumOstreams(sock, SCTP_MAX_STREAM)
+
+	// close socket on error
+	defer func() {
+		if err != nil {
+			syscall.Close(sock)
+		}
+	}()
+	if err = setDefaultSockopts(sock, af, ipv6only); err != nil {
+		return nil, err
+	}
+	err = setInitOpts(sock, options)
 	if err != nil {
 		return nil, err
 	}
 	if laddr != nil {
+		// If IP address and/or port was not provided so far, let's use the unspecified IPv4 or IPv6 address
+		if len(laddr.IPAddrs) == 0 {
+			if af == syscall.AF_INET {
+				laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv4zero})
+			} else if af == syscall.AF_INET6 {
+				laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv6zero})
+			}
+		}
 		err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
 		if err != nil {
 			return nil, err

+ 12 - 0
libnetwork/vendor/github.com/ishidawataru/sctp/sctp_unsupported.go

@@ -34,10 +34,18 @@ func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
 	return nil, ErrUnsupported
 }
 
+func ListenSCTPExt(net string, laddr *SCTPAddr, options InitMsg) (*SCTPListener, error) {
+	return nil, ErrUnsupported
+}
+
 func (ln *SCTPListener) Accept() (net.Conn, error) {
 	return nil, ErrUnsupported
 }
 
+func (ln *SCTPListener) AcceptSCTP() (*SCTPConn, error) {
+	return nil, ErrUnsupported
+}
+
 func (ln *SCTPListener) Close() error {
 	return ErrUnsupported
 }
@@ -45,3 +53,7 @@ func (ln *SCTPListener) Close() error {
 func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) {
 	return nil, ErrUnsupported
 }
+
+func DialSCTPExt(network string, laddr, raddr *SCTPAddr, options InitMsg) (*SCTPConn, error) {
+	return nil, ErrUnsupported
+}