diff --git a/libnetwork/cmd/proxy/main.go b/libnetwork/cmd/proxy/main.go index 3d51de6fb7..c2832b3fe3 100644 --- a/libnetwork/cmd/proxy/main.go +++ b/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) } diff --git a/libnetwork/cmd/proxy/network_proxy_test.go b/libnetwork/cmd/proxy/network_proxy_test.go index 2d226504b6..f0da09f3ca 100644 --- a/libnetwork/cmd/proxy/network_proxy_test.go +++ b/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) diff --git a/libnetwork/portmapper/mapper.go b/libnetwork/portmapper/mapper.go index be4157b0d5..47c99a9e34 100644 --- a/libnetwork/portmapper/mapper.go +++ b/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 } diff --git a/libnetwork/portmapper/proxy.go b/libnetwork/portmapper/proxy.go index 1183c33a7e..12e4122c05 100644 --- a/libnetwork/portmapper/proxy.go +++ b/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) diff --git a/libnetwork/types/types.go b/libnetwork/types/types.go index b102ba4c39..db1960c104 100644 --- a/libnetwork/types/types.go +++ b/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()) } diff --git a/libnetwork/vendor.conf b/libnetwork/vendor.conf index 27d0896e04..6d11985cdf 100644 --- a/libnetwork/vendor.conf +++ b/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 diff --git a/libnetwork/vendor/github.com/ishidawataru/sctp/GO_LICENSE b/libnetwork/vendor/github.com/ishidawataru/sctp/GO_LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/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. diff --git a/libnetwork/vendor/github.com/ishidawataru/sctp/ipsock_linux.go b/libnetwork/vendor/github.com/ishidawataru/sctp/ipsock_linux.go new file mode 100644 index 0000000000..f5632b72d2 --- /dev/null +++ b/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)) +} diff --git a/libnetwork/vendor/github.com/ishidawataru/sctp/sctp.go b/libnetwork/vendor/github.com/ishidawataru/sctp/sctp.go index cac1a889ca..30d619640c 100644 --- a/libnetwork/vendor/github.com/ishidawataru/sctp/sctp.go +++ b/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(¶m)), 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 { - s := syscall.RawSockaddrInet6{ - Family: syscall.AF_INET6, - Port: p, + var scopeid uint32 + ifi, err := net.InterfaceByName(ip.Zone) + if err == nil { + scopeid = uint32(ifi.Index) } - copy(s.Addr[:], ip) + s := syscall.RawSockaddrInet6{ + Family: syscall.AF_INET6, + Port: p, + Scope_id: scopeid, + } + 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(¶m)), 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) diff --git a/libnetwork/vendor/github.com/ishidawataru/sctp/sctp_linux.go b/libnetwork/vendor/github.com/ishidawataru/sctp/sctp_linux.go index f93ab8622a..5a6ad93785 100644 --- a/libnetwork/vendor/github.com/ishidawataru/sctp/sctp_linux.go +++ b/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 diff --git a/libnetwork/vendor/github.com/ishidawataru/sctp/sctp_unsupported.go b/libnetwork/vendor/github.com/ishidawataru/sctp/sctp_unsupported.go index adcbf78b46..e5415843dc 100644 --- a/libnetwork/vendor/github.com/ishidawataru/sctp/sctp_unsupported.go +++ b/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 +}