Explorar el Código

Merge pull request #33922 from ishidawataru/sctp

Support SCTP port mapping (bump up API to v1.37)
Sebastiaan van Stijn hace 7 años
padre
commit
079ed017b6
Se han modificado 25 ficheros con 1564 adiciones y 191 borrados
  1. 8 7
      api/swagger.yaml
  2. 2 0
      api/types/swarm/network.go
  3. 2 0
      daemon/cluster/executor/container/controller.go
  4. 6 0
      docs/api/version-history.md
  5. 1 1
      hack/dockerfile/binaries-commits
  6. 3 2
      vendor.conf
  7. 1 1
      vendor/github.com/docker/go-connections/nat/nat.go
  8. 0 1
      vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go
  9. 218 153
      vendor/github.com/docker/libnetwork/agent.pb.go
  10. 1 0
      vendor/github.com/docker/libnetwork/agent.proto
  11. 4 0
      vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go
  12. 6 0
      vendor/github.com/docker/libnetwork/drivers/windows/labels.go
  13. 43 15
      vendor/github.com/docker/libnetwork/drivers/windows/windows.go
  14. 25 1
      vendor/github.com/docker/libnetwork/iptables/iptables.go
  15. 4 3
      vendor/github.com/docker/libnetwork/portallocator/portallocator.go
  16. 56 3
      vendor/github.com/docker/libnetwork/portmapper/mapper.go
  17. 16 4
      vendor/github.com/docker/libnetwork/portmapper/proxy.go
  18. 6 0
      vendor/github.com/docker/libnetwork/service_linux.go
  19. 12 0
      vendor/github.com/docker/libnetwork/types/types.go
  20. 1 0
      vendor/github.com/docker/libnetwork/vendor.conf
  21. 201 0
      vendor/github.com/ishidawataru/sctp/LICENSE
  22. 18 0
      vendor/github.com/ishidawataru/sctp/README.md
  23. 656 0
      vendor/github.com/ishidawataru/sctp/sctp.go
  24. 227 0
      vendor/github.com/ishidawataru/sctp/sctp_linux.go
  25. 47 0
      vendor/github.com/ishidawataru/sctp/sctp_unsupported.go

+ 8 - 7
api/swagger.yaml

@@ -19,10 +19,10 @@ produces:
 consumes:
   - "application/json"
   - "text/plain"
-basePath: "/v1.36"
+basePath: "/v1.37"
 info:
   title: "Docker Engine API"
-  version: "1.36"
+  version: "1.37"
   x-logo:
     url: "https://docs.docker.com/images/logo-docker-main.png"
   description: |
@@ -49,7 +49,7 @@ info:
     the URL is not supported by the daemon, a HTTP `400 Bad Request` error message
     is returned.
 
-    If you omit the version-prefix, the current version of the API (v1.36) is used.
+    If you omit the version-prefix, the current version of the API (v1.37) is used.
     For example, calling `/info` is the same as calling `/v1.36/info`. Using the
     API without a version-prefix is deprecated and will be removed in a future release.
 
@@ -167,7 +167,7 @@ definitions:
       Type:
         type: "string"
         x-nullable: false
-        enum: ["tcp", "udp"]
+        enum: ["tcp", "udp", "sctp"]
     example:
       PrivatePort: 8080
       PublicPort: 80
@@ -801,7 +801,7 @@ definitions:
         description: |
           An object mapping ports to an empty object in the form:
 
-          `{"<port>/<tcp|udp>": {}}`
+          `{"<port>/<tcp|udp|sctp>": {}}`
         type: "object"
         additionalProperties:
           type: "object"
@@ -1066,8 +1066,8 @@ definitions:
       container's port-number and protocol as key in the format `<port>/<protocol>`,
       for example, `80/udp`.
 
-      If a container's port is mapped for both `tcp` and `udp`, two separate
-      entries are added to the mapping table.
+      If a container's port is mapped for multiple protocols, separate entries
+      are added to the mapping table.
     type: "object"
     additionalProperties:
       type: "array"
@@ -3046,6 +3046,7 @@ definitions:
         enum:
           - "tcp"
           - "udp"
+          - "sctp"
       TargetPort:
         description: "The port inside the container."
         type: "integer"

+ 2 - 0
api/types/swarm/network.go

@@ -62,6 +62,8 @@ const (
 	PortConfigProtocolTCP PortConfigProtocol = "tcp"
 	// PortConfigProtocolUDP UDP
 	PortConfigProtocolUDP PortConfigProtocol = "udp"
+	// PortConfigProtocolSCTP SCTP
+	PortConfigProtocolSCTP PortConfigProtocol = "sctp"
 )
 
 // EndpointVirtualIP represents the virtual ip of a port.

+ 2 - 0
daemon/cluster/executor/container/controller.go

@@ -621,6 +621,8 @@ func parsePortMap(portMap nat.PortMap) ([]*api.PortConfig, error) {
 			protocol = api.ProtocolTCP
 		case "udp":
 			protocol = api.ProtocolUDP
+		case "sctp":
+			protocol = api.ProtocolSCTP
 		default:
 			return nil, fmt.Errorf("invalid protocol: %s", parts[1])
 		}

+ 6 - 0
docs/api/version-history.md

@@ -13,6 +13,12 @@ keywords: "API, Docker, rcli, REST, documentation"
      will be rejected.
 -->
 
+## v1.37 API changes
+
+[Docker Engine API v1.37](https://docs.docker.com/engine/api/v1.36/) documentation
+
+* `POST /containers/create` and `POST /services/create` now supports exposing SCTP ports.
+
 ## v1.36 API changes
 
 [Docker Engine API v1.36](https://docs.docker.com/engine/api/v1.36/) documentation

+ 1 - 1
hack/dockerfile/binaries-commits

@@ -16,7 +16,7 @@ TINI_COMMIT=949e6facb77383876aeff8a6944dde66b3089574
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
 # updating the binary version, consider updating github.com/docker/libnetwork
 # in vendor.conf accordingly
-LIBNETWORK_COMMIT=20dd462e0a0e883437a274bd61df4bc4de980830
+LIBNETWORK_COMMIT=ed2130d117c11c542327b4d5216a5db36770bc65
 VNDR_COMMIT=a6e196d8b4b0cbbdc29aebdb20c59ac6926bb384
 
 # Linting

+ 3 - 2
vendor.conf

@@ -16,7 +16,7 @@ github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
 golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
 github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
-github.com/docker/go-connections 98e7d807e5d804e4e42a98d74d1dd695321224ef
+github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
 golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
 github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
 github.com/pmezard/go-difflib v1.0.0
@@ -33,7 +33,7 @@ github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
 #get libnetwork packages
 
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/binaries-commits accordingly
-github.com/docker/libnetwork 20dd462e0a0e883437a274bd61df4bc4de980830
+github.com/docker/libnetwork ed2130d117c11c542327b4d5216a5db36770bc65
 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
@@ -57,6 +57,7 @@ github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
 github.com/hashicorp/consul v0.5.2
 github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
 github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
+github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
 
 # get graph and distribution packages
 github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c

+ 1 - 1
vendor/github.com/docker/go-connections/nat/nat.go

@@ -113,7 +113,7 @@ func SplitProtoPort(rawPort string) (string, string) {
 }
 
 func validateProto(proto string) bool {
-	for _, availableProto := range []string{"tcp", "udp"} {
+	for _, availableProto := range []string{"tcp", "udp", "sctp"} {
 		if availableProto == proto {
 			return true
 		}

+ 0 - 1
vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go

@@ -4,7 +4,6 @@ package tlsconfig
 
 import (
 	"crypto/x509"
-
 )
 
 // SystemCertPool returns an new empty cert pool,

+ 218 - 153
vendor/github.com/docker/libnetwork/agent.pb.go

@@ -1,6 +1,5 @@
-// Code generated by protoc-gen-gogo.
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: agent.proto
-// DO NOT EDIT!
 
 /*
 	Package libnetwork is a generated protocol buffer package.
@@ -20,9 +19,6 @@ import math "math"
 import _ "github.com/gogo/protobuf/gogoproto"
 
 import strings "strings"
-import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
-import sort "sort"
-import strconv "strconv"
 import reflect "reflect"
 
 import io "io"
@@ -34,22 +30,27 @@ var _ = math.Inf
 
 // This is a compile-time assertion to ensure that this generated file
 // is compatible with the proto package it is being compiled against.
-const _ = proto.GoGoProtoPackageIsVersion1
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
 
 type PortConfig_Protocol int32
 
 const (
-	ProtocolTCP PortConfig_Protocol = 0
-	ProtocolUDP PortConfig_Protocol = 1
+	ProtocolTCP  PortConfig_Protocol = 0
+	ProtocolUDP  PortConfig_Protocol = 1
+	ProtocolSCTP PortConfig_Protocol = 2
 )
 
 var PortConfig_Protocol_name = map[int32]string{
 	0: "TCP",
 	1: "UDP",
+	2: "SCTP",
 }
 var PortConfig_Protocol_value = map[string]int32{
-	"TCP": 0,
-	"UDP": 1,
+	"TCP":  0,
+	"UDP":  1,
+	"SCTP": 2,
 }
 
 func (x PortConfig_Protocol) String() string {
@@ -60,7 +61,7 @@ func (PortConfig_Protocol) EnumDescriptor() ([]byte, []int) { return fileDescrip
 // EndpointRecord specifies all the endpoint specific information that
 // needs to gossiped to nodes participating in the network.
 type EndpointRecord struct {
-	// Name of the endpoint
+	// Name of the container
 	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
 	// Service name of the service to which this endpoint belongs.
 	ServiceName string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
@@ -82,6 +83,41 @@ func (m *EndpointRecord) Reset()                    { *m = EndpointRecord{} }
 func (*EndpointRecord) ProtoMessage()               {}
 func (*EndpointRecord) Descriptor() ([]byte, []int) { return fileDescriptorAgent, []int{0} }
 
+func (m *EndpointRecord) GetName() string {
+	if m != nil {
+		return m.Name
+	}
+	return ""
+}
+
+func (m *EndpointRecord) GetServiceName() string {
+	if m != nil {
+		return m.ServiceName
+	}
+	return ""
+}
+
+func (m *EndpointRecord) GetServiceID() string {
+	if m != nil {
+		return m.ServiceID
+	}
+	return ""
+}
+
+func (m *EndpointRecord) GetVirtualIP() string {
+	if m != nil {
+		return m.VirtualIP
+	}
+	return ""
+}
+
+func (m *EndpointRecord) GetEndpointIP() string {
+	if m != nil {
+		return m.EndpointIP
+	}
+	return ""
+}
+
 func (m *EndpointRecord) GetIngressPorts() []*PortConfig {
 	if m != nil {
 		return m.IngressPorts
@@ -89,6 +125,20 @@ func (m *EndpointRecord) GetIngressPorts() []*PortConfig {
 	return nil
 }
 
+func (m *EndpointRecord) GetAliases() []string {
+	if m != nil {
+		return m.Aliases
+	}
+	return nil
+}
+
+func (m *EndpointRecord) GetTaskAliases() []string {
+	if m != nil {
+		return m.TaskAliases
+	}
+	return nil
+}
+
 // PortConfig specifies an exposed port which can be
 // addressed using the given name. This can be later queried
 // using a service discovery api or a DNS SRV query. The node
@@ -115,6 +165,34 @@ func (m *PortConfig) Reset()                    { *m = PortConfig{} }
 func (*PortConfig) ProtoMessage()               {}
 func (*PortConfig) Descriptor() ([]byte, []int) { return fileDescriptorAgent, []int{1} }
 
+func (m *PortConfig) GetName() string {
+	if m != nil {
+		return m.Name
+	}
+	return ""
+}
+
+func (m *PortConfig) GetProtocol() PortConfig_Protocol {
+	if m != nil {
+		return m.Protocol
+	}
+	return ProtocolTCP
+}
+
+func (m *PortConfig) GetTargetPort() uint32 {
+	if m != nil {
+		return m.TargetPort
+	}
+	return 0
+}
+
+func (m *PortConfig) GetPublishedPort() uint32 {
+	if m != nil {
+		return m.PublishedPort
+	}
+	return 0
+}
+
 func init() {
 	proto.RegisterType((*EndpointRecord)(nil), "libnetwork.EndpointRecord")
 	proto.RegisterType((*PortConfig)(nil), "libnetwork.PortConfig")
@@ -160,74 +238,57 @@ func valueToGoStringAgent(v interface{}, typ string) string {
 	pv := reflect.Indirect(rv).Interface()
 	return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
 }
-func extensionToGoStringAgent(e map[int32]github_com_gogo_protobuf_proto.Extension) string {
-	if e == nil {
-		return "nil"
-	}
-	s := "map[int32]proto.Extension{"
-	keys := make([]int, 0, len(e))
-	for k := range e {
-		keys = append(keys, int(k))
-	}
-	sort.Ints(keys)
-	ss := []string{}
-	for _, k := range keys {
-		ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString())
-	}
-	s += strings.Join(ss, ",") + "}"
-	return s
-}
-func (m *EndpointRecord) Marshal() (data []byte, err error) {
+func (m *EndpointRecord) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
-	data = make([]byte, size)
-	n, err := m.MarshalTo(data)
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
 	if err != nil {
 		return nil, err
 	}
-	return data[:n], nil
+	return dAtA[:n], nil
 }
 
-func (m *EndpointRecord) MarshalTo(data []byte) (int, error) {
+func (m *EndpointRecord) MarshalTo(dAtA []byte) (int, error) {
 	var i int
 	_ = i
 	var l int
 	_ = l
 	if len(m.Name) > 0 {
-		data[i] = 0xa
+		dAtA[i] = 0xa
 		i++
-		i = encodeVarintAgent(data, i, uint64(len(m.Name)))
-		i += copy(data[i:], m.Name)
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.Name)))
+		i += copy(dAtA[i:], m.Name)
 	}
 	if len(m.ServiceName) > 0 {
-		data[i] = 0x12
+		dAtA[i] = 0x12
 		i++
-		i = encodeVarintAgent(data, i, uint64(len(m.ServiceName)))
-		i += copy(data[i:], m.ServiceName)
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.ServiceName)))
+		i += copy(dAtA[i:], m.ServiceName)
 	}
 	if len(m.ServiceID) > 0 {
-		data[i] = 0x1a
+		dAtA[i] = 0x1a
 		i++
-		i = encodeVarintAgent(data, i, uint64(len(m.ServiceID)))
-		i += copy(data[i:], m.ServiceID)
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.ServiceID)))
+		i += copy(dAtA[i:], m.ServiceID)
 	}
 	if len(m.VirtualIP) > 0 {
-		data[i] = 0x22
+		dAtA[i] = 0x22
 		i++
-		i = encodeVarintAgent(data, i, uint64(len(m.VirtualIP)))
-		i += copy(data[i:], m.VirtualIP)
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.VirtualIP)))
+		i += copy(dAtA[i:], m.VirtualIP)
 	}
 	if len(m.EndpointIP) > 0 {
-		data[i] = 0x2a
+		dAtA[i] = 0x2a
 		i++
-		i = encodeVarintAgent(data, i, uint64(len(m.EndpointIP)))
-		i += copy(data[i:], m.EndpointIP)
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.EndpointIP)))
+		i += copy(dAtA[i:], m.EndpointIP)
 	}
 	if len(m.IngressPorts) > 0 {
 		for _, msg := range m.IngressPorts {
-			data[i] = 0x32
+			dAtA[i] = 0x32
 			i++
-			i = encodeVarintAgent(data, i, uint64(msg.Size()))
-			n, err := msg.MarshalTo(data[i:])
+			i = encodeVarintAgent(dAtA, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(dAtA[i:])
 			if err != nil {
 				return 0, err
 			}
@@ -236,101 +297,101 @@ func (m *EndpointRecord) MarshalTo(data []byte) (int, error) {
 	}
 	if len(m.Aliases) > 0 {
 		for _, s := range m.Aliases {
-			data[i] = 0x3a
+			dAtA[i] = 0x3a
 			i++
 			l = len(s)
 			for l >= 1<<7 {
-				data[i] = uint8(uint64(l)&0x7f | 0x80)
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
 				l >>= 7
 				i++
 			}
-			data[i] = uint8(l)
+			dAtA[i] = uint8(l)
 			i++
-			i += copy(data[i:], s)
+			i += copy(dAtA[i:], s)
 		}
 	}
 	if len(m.TaskAliases) > 0 {
 		for _, s := range m.TaskAliases {
-			data[i] = 0x42
+			dAtA[i] = 0x42
 			i++
 			l = len(s)
 			for l >= 1<<7 {
-				data[i] = uint8(uint64(l)&0x7f | 0x80)
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
 				l >>= 7
 				i++
 			}
-			data[i] = uint8(l)
+			dAtA[i] = uint8(l)
 			i++
-			i += copy(data[i:], s)
+			i += copy(dAtA[i:], s)
 		}
 	}
 	return i, nil
 }
 
-func (m *PortConfig) Marshal() (data []byte, err error) {
+func (m *PortConfig) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
-	data = make([]byte, size)
-	n, err := m.MarshalTo(data)
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
 	if err != nil {
 		return nil, err
 	}
-	return data[:n], nil
+	return dAtA[:n], nil
 }
 
-func (m *PortConfig) MarshalTo(data []byte) (int, error) {
+func (m *PortConfig) MarshalTo(dAtA []byte) (int, error) {
 	var i int
 	_ = i
 	var l int
 	_ = l
 	if len(m.Name) > 0 {
-		data[i] = 0xa
+		dAtA[i] = 0xa
 		i++
-		i = encodeVarintAgent(data, i, uint64(len(m.Name)))
-		i += copy(data[i:], m.Name)
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.Name)))
+		i += copy(dAtA[i:], m.Name)
 	}
 	if m.Protocol != 0 {
-		data[i] = 0x10
+		dAtA[i] = 0x10
 		i++
-		i = encodeVarintAgent(data, i, uint64(m.Protocol))
+		i = encodeVarintAgent(dAtA, i, uint64(m.Protocol))
 	}
 	if m.TargetPort != 0 {
-		data[i] = 0x18
+		dAtA[i] = 0x18
 		i++
-		i = encodeVarintAgent(data, i, uint64(m.TargetPort))
+		i = encodeVarintAgent(dAtA, i, uint64(m.TargetPort))
 	}
 	if m.PublishedPort != 0 {
-		data[i] = 0x20
+		dAtA[i] = 0x20
 		i++
-		i = encodeVarintAgent(data, i, uint64(m.PublishedPort))
+		i = encodeVarintAgent(dAtA, i, uint64(m.PublishedPort))
 	}
 	return i, nil
 }
 
-func encodeFixed64Agent(data []byte, offset int, v uint64) int {
-	data[offset] = uint8(v)
-	data[offset+1] = uint8(v >> 8)
-	data[offset+2] = uint8(v >> 16)
-	data[offset+3] = uint8(v >> 24)
-	data[offset+4] = uint8(v >> 32)
-	data[offset+5] = uint8(v >> 40)
-	data[offset+6] = uint8(v >> 48)
-	data[offset+7] = uint8(v >> 56)
+func encodeFixed64Agent(dAtA []byte, offset int, v uint64) int {
+	dAtA[offset] = uint8(v)
+	dAtA[offset+1] = uint8(v >> 8)
+	dAtA[offset+2] = uint8(v >> 16)
+	dAtA[offset+3] = uint8(v >> 24)
+	dAtA[offset+4] = uint8(v >> 32)
+	dAtA[offset+5] = uint8(v >> 40)
+	dAtA[offset+6] = uint8(v >> 48)
+	dAtA[offset+7] = uint8(v >> 56)
 	return offset + 8
 }
-func encodeFixed32Agent(data []byte, offset int, v uint32) int {
-	data[offset] = uint8(v)
-	data[offset+1] = uint8(v >> 8)
-	data[offset+2] = uint8(v >> 16)
-	data[offset+3] = uint8(v >> 24)
+func encodeFixed32Agent(dAtA []byte, offset int, v uint32) int {
+	dAtA[offset] = uint8(v)
+	dAtA[offset+1] = uint8(v >> 8)
+	dAtA[offset+2] = uint8(v >> 16)
+	dAtA[offset+3] = uint8(v >> 24)
 	return offset + 4
 }
-func encodeVarintAgent(data []byte, offset int, v uint64) int {
+func encodeVarintAgent(dAtA []byte, offset int, v uint64) int {
 	for v >= 1<<7 {
-		data[offset] = uint8(v&0x7f | 0x80)
+		dAtA[offset] = uint8(v&0x7f | 0x80)
 		v >>= 7
 		offset++
 	}
-	data[offset] = uint8(v)
+	dAtA[offset] = uint8(v)
 	return offset + 1
 }
 func (m *EndpointRecord) Size() (n int) {
@@ -447,8 +508,8 @@ func valueToStringAgent(v interface{}) string {
 	pv := reflect.Indirect(rv).Interface()
 	return fmt.Sprintf("*%v", pv)
 }
-func (m *EndpointRecord) Unmarshal(data []byte) error {
-	l := len(data)
+func (m *EndpointRecord) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
 	iNdEx := 0
 	for iNdEx < l {
 		preIndex := iNdEx
@@ -460,7 +521,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 			if iNdEx >= l {
 				return io.ErrUnexpectedEOF
 			}
-			b := data[iNdEx]
+			b := dAtA[iNdEx]
 			iNdEx++
 			wire |= (uint64(b) & 0x7F) << shift
 			if b < 0x80 {
@@ -488,7 +549,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				stringLen |= (uint64(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -503,7 +564,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.Name = string(data[iNdEx:postIndex])
+			m.Name = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
 		case 2:
 			if wireType != 2 {
@@ -517,7 +578,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				stringLen |= (uint64(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -532,7 +593,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.ServiceName = string(data[iNdEx:postIndex])
+			m.ServiceName = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
 		case 3:
 			if wireType != 2 {
@@ -546,7 +607,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				stringLen |= (uint64(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -561,7 +622,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.ServiceID = string(data[iNdEx:postIndex])
+			m.ServiceID = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
 		case 4:
 			if wireType != 2 {
@@ -575,7 +636,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				stringLen |= (uint64(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -590,7 +651,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.VirtualIP = string(data[iNdEx:postIndex])
+			m.VirtualIP = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
 		case 5:
 			if wireType != 2 {
@@ -604,7 +665,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				stringLen |= (uint64(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -619,7 +680,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.EndpointIP = string(data[iNdEx:postIndex])
+			m.EndpointIP = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
 		case 6:
 			if wireType != 2 {
@@ -633,7 +694,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				msglen |= (int(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -648,7 +709,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 				return io.ErrUnexpectedEOF
 			}
 			m.IngressPorts = append(m.IngressPorts, &PortConfig{})
-			if err := m.IngressPorts[len(m.IngressPorts)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
+			if err := m.IngressPorts[len(m.IngressPorts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
 				return err
 			}
 			iNdEx = postIndex
@@ -664,7 +725,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				stringLen |= (uint64(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -679,7 +740,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.Aliases = append(m.Aliases, string(data[iNdEx:postIndex]))
+			m.Aliases = append(m.Aliases, string(dAtA[iNdEx:postIndex]))
 			iNdEx = postIndex
 		case 8:
 			if wireType != 2 {
@@ -693,7 +754,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				stringLen |= (uint64(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -708,11 +769,11 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.TaskAliases = append(m.TaskAliases, string(data[iNdEx:postIndex]))
+			m.TaskAliases = append(m.TaskAliases, string(dAtA[iNdEx:postIndex]))
 			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
-			skippy, err := skipAgent(data[iNdEx:])
+			skippy, err := skipAgent(dAtA[iNdEx:])
 			if err != nil {
 				return err
 			}
@@ -731,8 +792,8 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
 	}
 	return nil
 }
-func (m *PortConfig) Unmarshal(data []byte) error {
-	l := len(data)
+func (m *PortConfig) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
 	iNdEx := 0
 	for iNdEx < l {
 		preIndex := iNdEx
@@ -744,7 +805,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
 			if iNdEx >= l {
 				return io.ErrUnexpectedEOF
 			}
-			b := data[iNdEx]
+			b := dAtA[iNdEx]
 			iNdEx++
 			wire |= (uint64(b) & 0x7F) << shift
 			if b < 0x80 {
@@ -772,7 +833,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				stringLen |= (uint64(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -787,7 +848,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.Name = string(data[iNdEx:postIndex])
+			m.Name = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
 		case 2:
 			if wireType != 0 {
@@ -801,7 +862,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				m.Protocol |= (PortConfig_Protocol(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -820,7 +881,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				m.TargetPort |= (uint32(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -839,7 +900,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
 				if iNdEx >= l {
 					return io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				m.PublishedPort |= (uint32(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -848,7 +909,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
 			}
 		default:
 			iNdEx = preIndex
-			skippy, err := skipAgent(data[iNdEx:])
+			skippy, err := skipAgent(dAtA[iNdEx:])
 			if err != nil {
 				return err
 			}
@@ -867,8 +928,8 @@ func (m *PortConfig) Unmarshal(data []byte) error {
 	}
 	return nil
 }
-func skipAgent(data []byte) (n int, err error) {
-	l := len(data)
+func skipAgent(dAtA []byte) (n int, err error) {
+	l := len(dAtA)
 	iNdEx := 0
 	for iNdEx < l {
 		var wire uint64
@@ -879,7 +940,7 @@ func skipAgent(data []byte) (n int, err error) {
 			if iNdEx >= l {
 				return 0, io.ErrUnexpectedEOF
 			}
-			b := data[iNdEx]
+			b := dAtA[iNdEx]
 			iNdEx++
 			wire |= (uint64(b) & 0x7F) << shift
 			if b < 0x80 {
@@ -897,7 +958,7 @@ func skipAgent(data []byte) (n int, err error) {
 					return 0, io.ErrUnexpectedEOF
 				}
 				iNdEx++
-				if data[iNdEx-1] < 0x80 {
+				if dAtA[iNdEx-1] < 0x80 {
 					break
 				}
 			}
@@ -914,7 +975,7 @@ func skipAgent(data []byte) (n int, err error) {
 				if iNdEx >= l {
 					return 0, io.ErrUnexpectedEOF
 				}
-				b := data[iNdEx]
+				b := dAtA[iNdEx]
 				iNdEx++
 				length |= (int(b) & 0x7F) << shift
 				if b < 0x80 {
@@ -937,7 +998,7 @@ func skipAgent(data []byte) (n int, err error) {
 					if iNdEx >= l {
 						return 0, io.ErrUnexpectedEOF
 					}
-					b := data[iNdEx]
+					b := dAtA[iNdEx]
 					iNdEx++
 					innerWire |= (uint64(b) & 0x7F) << shift
 					if b < 0x80 {
@@ -948,7 +1009,7 @@ func skipAgent(data []byte) (n int, err error) {
 				if innerWireType == 4 {
 					break
 				}
-				next, err := skipAgent(data[start:])
+				next, err := skipAgent(dAtA[start:])
 				if err != nil {
 					return 0, err
 				}
@@ -972,32 +1033,36 @@ var (
 	ErrIntOverflowAgent   = fmt.Errorf("proto: integer overflow")
 )
 
+func init() { proto.RegisterFile("agent.proto", fileDescriptorAgent) }
+
 var fileDescriptorAgent = []byte{
-	// 413 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0xbf, 0xae, 0xd3, 0x30,
-	0x14, 0x87, 0x9b, 0xdb, 0x70, 0x6f, 0x73, 0x72, 0x13, 0xae, 0x2c, 0x84, 0xa2, 0x0e, 0x69, 0xa9,
-	0x84, 0x74, 0x07, 0x94, 0x2b, 0x95, 0xb1, 0x13, 0x6d, 0x19, 0xb2, 0xa0, 0xc8, 0xfc, 0x59, 0xa3,
-	0xb4, 0x31, 0xc1, 0x6a, 0x88, 0x23, 0xdb, 0x2d, 0x2b, 0x23, 0xe2, 0x1d, 0x98, 0x78, 0x19, 0x26,
-	0xc4, 0xc8, 0x84, 0x68, 0x57, 0x16, 0x1e, 0x01, 0xdb, 0x49, 0x5a, 0x21, 0x75, 0x38, 0x92, 0xf3,
-	0xfd, 0xbe, 0xe3, 0x1c, 0x1f, 0x70, 0xb3, 0x82, 0x54, 0x32, 0xaa, 0x39, 0x93, 0x0c, 0x41, 0x49,
-	0x57, 0x15, 0x91, 0x1f, 0x18, 0xdf, 0x0c, 0x1f, 0x14, 0xac, 0x60, 0x06, 0xdf, 0xe9, 0x53, 0x63,
-	0x4c, 0xbe, 0x5f, 0x80, 0xff, 0xbc, 0xca, 0x6b, 0x46, 0x2b, 0x89, 0xc9, 0x9a, 0xf1, 0x1c, 0x21,
-	0xb0, 0xab, 0xec, 0x3d, 0x09, 0xac, 0xb1, 0x75, 0xeb, 0x60, 0x73, 0x46, 0x8f, 0xe0, 0x5a, 0x10,
-	0xbe, 0xa3, 0x6b, 0x92, 0x9a, 0xec, 0xc2, 0x64, 0x6e, 0xcb, 0x5e, 0x68, 0xe5, 0x09, 0x40, 0xa7,
-	0xd0, 0x3c, 0xe8, 0x6b, 0x61, 0xee, 0x1d, 0x7e, 0x8d, 0x9c, 0x97, 0x0d, 0x8d, 0x97, 0xd8, 0x69,
-	0x85, 0x38, 0xd7, 0xf6, 0x8e, 0x72, 0xb9, 0xcd, 0xca, 0x94, 0xd6, 0x81, 0x7d, 0xb2, 0xdf, 0x34,
-	0x34, 0x4e, 0xb0, 0xd3, 0x0a, 0x71, 0x8d, 0xee, 0xc0, 0x25, 0xed, 0x90, 0x5a, 0xbf, 0x67, 0x74,
-	0x5f, 0xe9, 0xd0, 0xcd, 0xae, 0x7c, 0xe8, 0x14, 0xd5, 0x30, 0x03, 0x8f, 0x56, 0x05, 0x27, 0x42,
-	0xa4, 0x35, 0xe3, 0x52, 0x04, 0x97, 0xe3, 0xfe, 0xad, 0x3b, 0x7d, 0x18, 0x9d, 0x16, 0x12, 0x25,
-	0x2a, 0x58, 0xb0, 0xea, 0x2d, 0x2d, 0xf0, 0x75, 0x2b, 0x6b, 0x24, 0x50, 0x00, 0x57, 0x59, 0x49,
-	0x33, 0x41, 0x44, 0x70, 0xa5, 0xda, 0x1c, 0xdc, 0x7d, 0xea, 0x35, 0xc8, 0x4c, 0x6c, 0xd2, 0x2e,
-	0x1e, 0x98, 0xd8, 0xd5, 0xec, 0x59, 0x83, 0x26, 0x7f, 0x2c, 0x80, 0xd3, 0xcd, 0x67, 0x97, 0x39,
-	0x83, 0x81, 0x59, 0xfe, 0x9a, 0x95, 0x66, 0x91, 0xfe, 0x74, 0x74, 0x7e, 0xae, 0x28, 0x69, 0x35,
-	0x7c, 0x6c, 0x40, 0x23, 0x50, 0xbf, 0xe3, 0x05, 0x91, 0xe6, 0x61, 0x66, 0xcf, 0x1e, 0x86, 0x06,
-	0xe9, 0x4e, 0xf4, 0x18, 0xfc, 0x7a, 0xbb, 0x2a, 0xa9, 0x78, 0x47, 0xf2, 0xc6, 0xb1, 0x8d, 0xe3,
-	0x1d, 0xa9, 0xd6, 0x26, 0x4b, 0x18, 0x74, 0xb7, 0xab, 0x07, 0xf7, 0x5f, 0x2d, 0x92, 0x9b, 0xde,
-	0xf0, 0xfe, 0xe7, 0x2f, 0x63, 0xb7, 0xc3, 0x0a, 0xe9, 0xe4, 0xf5, 0x32, 0xb9, 0xb1, 0xfe, 0x4f,
-	0x14, 0x1a, 0xda, 0x9f, 0xbe, 0x86, 0xbd, 0x79, 0xf0, 0x73, 0x1f, 0xf6, 0xfe, 0xee, 0x43, 0xeb,
-	0xe3, 0x21, 0xb4, 0xbe, 0xa9, 0xfa, 0xa1, 0xea, 0xb7, 0xaa, 0xd5, 0xa5, 0x99, 0xf8, 0xe9, 0xbf,
-	0x00, 0x00, 0x00, 0xff, 0xff, 0xc9, 0x63, 0x1a, 0x0f, 0x90, 0x02, 0x00, 0x00,
+	// 437 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xc1, 0x6e, 0xd3, 0x30,
+	0x18, 0xc7, 0x9b, 0x36, 0x6c, 0xcd, 0x97, 0xb6, 0x54, 0x16, 0x42, 0x51, 0x0e, 0x69, 0xa8, 0x84,
+	0xd4, 0x03, 0xea, 0xa4, 0x71, 0xdc, 0x89, 0xb5, 0x1c, 0x72, 0x41, 0x96, 0xd7, 0x71, 0x0d, 0x69,
+	0x63, 0x82, 0xb5, 0x10, 0x47, 0xb6, 0x37, 0xae, 0xdc, 0x40, 0x7b, 0x87, 0x9d, 0x78, 0x19, 0x4e,
+	0x88, 0x23, 0xa7, 0x89, 0xe5, 0x09, 0x78, 0x04, 0x64, 0x27, 0x5e, 0x35, 0x69, 0x37, 0xfb, 0xf7,
+	0xff, 0xd9, 0xfa, 0xbe, 0x3f, 0xf8, 0x59, 0x41, 0x2b, 0xb5, 0xac, 0x05, 0x57, 0x1c, 0x41, 0xc9,
+	0xb6, 0x15, 0x55, 0x5f, 0xb8, 0xb8, 0x08, 0x9f, 0x15, 0xbc, 0xe0, 0x06, 0x1f, 0xe9, 0x53, 0x6b,
+	0xcc, 0x7f, 0xf5, 0x61, 0xf2, 0xb6, 0xca, 0x6b, 0xce, 0x2a, 0x45, 0xe8, 0x8e, 0x8b, 0x1c, 0x21,
+	0x70, 0xab, 0xec, 0x33, 0x0d, 0x9c, 0xd8, 0x59, 0x78, 0xc4, 0x9c, 0xd1, 0x0b, 0x18, 0x49, 0x2a,
+	0xae, 0xd8, 0x8e, 0xa6, 0x26, 0xeb, 0x9b, 0xcc, 0xef, 0xd8, 0x3b, 0xad, 0xbc, 0x02, 0xb0, 0x0a,
+	0xcb, 0x83, 0x81, 0x16, 0x4e, 0xc7, 0xcd, 0xed, 0xcc, 0x3b, 0x6b, 0x69, 0xb2, 0x26, 0x5e, 0x27,
+	0x24, 0xb9, 0xb6, 0xaf, 0x98, 0x50, 0x97, 0x59, 0x99, 0xb2, 0x3a, 0x70, 0xf7, 0xf6, 0xfb, 0x96,
+	0x26, 0x98, 0x78, 0x9d, 0x90, 0xd4, 0xe8, 0x08, 0x7c, 0xda, 0x0d, 0xa9, 0xf5, 0x27, 0x46, 0x9f,
+	0x34, 0xb7, 0x33, 0xb0, 0xb3, 0x27, 0x98, 0x80, 0x55, 0x92, 0x1a, 0x9d, 0xc0, 0x98, 0x55, 0x85,
+	0xa0, 0x52, 0xa6, 0x35, 0x17, 0x4a, 0x06, 0x07, 0xf1, 0x60, 0xe1, 0x1f, 0x3f, 0x5f, 0xee, 0x0b,
+	0x59, 0x62, 0x2e, 0xd4, 0x8a, 0x57, 0x1f, 0x59, 0x41, 0x46, 0x9d, 0xac, 0x91, 0x44, 0x01, 0x1c,
+	0x66, 0x25, 0xcb, 0x24, 0x95, 0xc1, 0x61, 0x3c, 0x58, 0x78, 0xc4, 0x5e, 0x75, 0x0d, 0x2a, 0x93,
+	0x17, 0xa9, 0x8d, 0x87, 0x26, 0xf6, 0x35, 0x7b, 0xd3, 0xa2, 0xf9, 0xb7, 0x3e, 0xc0, 0xfe, 0xe7,
+	0x47, 0xcb, 0x3c, 0x81, 0xa1, 0x29, 0x7f, 0xc7, 0x4b, 0x53, 0xe4, 0xe4, 0x78, 0xf6, 0xf8, 0x5c,
+	0x4b, 0xdc, 0x69, 0xe4, 0xfe, 0x01, 0x9a, 0x81, 0xaf, 0x32, 0x51, 0x50, 0x65, 0x16, 0x33, 0x3d,
+	0x8f, 0x09, 0xb4, 0x48, 0xbf, 0x44, 0x2f, 0x61, 0x52, 0x5f, 0x6e, 0x4b, 0x26, 0x3f, 0xd1, 0xbc,
+	0x75, 0x5c, 0xe3, 0x8c, 0xef, 0xa9, 0xd6, 0xe6, 0x1f, 0x60, 0x68, 0x7f, 0x47, 0x01, 0x0c, 0x36,
+	0x2b, 0x3c, 0xed, 0x85, 0x4f, 0xaf, 0x6f, 0x62, 0xdf, 0xe2, 0xcd, 0x0a, 0xeb, 0xe4, 0x7c, 0x8d,
+	0xa7, 0xce, 0xc3, 0xe4, 0x7c, 0x8d, 0x51, 0x08, 0xee, 0xd9, 0x6a, 0x83, 0xa7, 0xfd, 0x70, 0x7a,
+	0x7d, 0x13, 0x8f, 0x6c, 0xa4, 0x59, 0xe8, 0x7e, 0xff, 0x11, 0xf5, 0x4e, 0x83, 0x3f, 0x77, 0x51,
+	0xef, 0xdf, 0x5d, 0xe4, 0x7c, 0x6d, 0x22, 0xe7, 0x67, 0x13, 0x39, 0xbf, 0x9b, 0xc8, 0xf9, 0xdb,
+	0x44, 0xce, 0xf6, 0xc0, 0x6c, 0xf3, 0xfa, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xce, 0x12, 0x15,
+	0x67, 0xac, 0x02, 0x00, 0x00,
 }

+ 1 - 0
vendor/github.com/docker/libnetwork/agent.proto

@@ -51,6 +51,7 @@ message PortConfig {
 
 		TCP = 0 [(gogoproto.enumvalue_customname) = "ProtocolTCP"];
 		UDP = 1 [(gogoproto.enumvalue_customname) = "ProtocolUDP"];
+		SCTP = 2 [(gogoproto.enumvalue_customname) = "ProtocolSCTP"];
 	}
 
 	// Name for the port. If provided the port information can

+ 4 - 0
vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go

@@ -7,6 +7,7 @@ import (
 	"net"
 
 	"github.com/docker/libnetwork/types"
+	"github.com/ishidawataru/sctp"
 	"github.com/sirupsen/logrus"
 )
 
@@ -92,6 +93,9 @@ func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHos
 	case *net.UDPAddr:
 		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
 		return nil
+	case *sctp.SCTPAddr:
+		bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
+		return nil
 	default:
 		// For completeness
 		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))

+ 6 - 0
vendor/github.com/docker/libnetwork/drivers/windows/labels.go

@@ -42,4 +42,10 @@ const (
 
 	// DisableGatewayDNS label
 	DisableGatewayDNS = "com.docker.network.windowsshim.disable_gatewaydns"
+
+	// EnableOutboundNat label
+	EnableOutboundNat = "com.docker.network.windowsshim.enable_outboundnat"
+
+	// OutboundNatExceptions label
+	OutboundNatExceptions = "com.docker.network.windowsshim.outboundnat_exceptions"
 )

+ 43 - 15
vendor/github.com/docker/libnetwork/drivers/windows/windows.go

@@ -20,6 +20,7 @@ import (
 	"sync"
 
 	"github.com/Microsoft/hcsshim"
+	"github.com/docker/docker/pkg/system"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/driverapi"
@@ -30,21 +31,23 @@ import (
 
 // networkConfiguration for network specific configuration
 type networkConfiguration struct {
-	ID                 string
-	Type               string
-	Name               string
-	HnsID              string
-	RDID               string
-	VLAN               uint
-	VSID               uint
-	DNSServers         string
-	MacPools           []hcsshim.MacPool
-	DNSSuffix          string
-	SourceMac          string
-	NetworkAdapterName string
-	dbIndex            uint64
-	dbExists           bool
-	DisableGatewayDNS  bool
+	ID                    string
+	Type                  string
+	Name                  string
+	HnsID                 string
+	RDID                  string
+	VLAN                  uint
+	VSID                  uint
+	DNSServers            string
+	MacPools              []hcsshim.MacPool
+	DNSSuffix             string
+	SourceMac             string
+	NetworkAdapterName    string
+	dbIndex               uint64
+	dbExists              bool
+	DisableGatewayDNS     bool
+	EnableOutboundNat     bool
+	OutboundNatExceptions []string
 }
 
 // endpointConfiguration represents the user specified configuration for the sandbox endpoint
@@ -208,6 +211,18 @@ func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string
 				return nil, err
 			}
 			config.VSID = uint(vsid)
+		case EnableOutboundNat:
+			if system.GetOSVersion().Build <= 16236 {
+				return nil, fmt.Errorf("Invalid network option. OutboundNat is not supported on this OS version")
+			}
+			b, err := strconv.ParseBool(value)
+			if err != nil {
+				return nil, err
+			}
+			config.EnableOutboundNat = b
+		case OutboundNatExceptions:
+			s := strings.Split(value, ",")
+			config.OutboundNatExceptions = s
 		}
 	}
 
@@ -609,6 +624,19 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 
 	endpointStruct.DisableICC = epOption.DisableICC
 
+	// Inherit OutboundNat policy from the network
+	if n.config.EnableOutboundNat {
+		outboundNatPolicy, err := json.Marshal(hcsshim.OutboundNatPolicy{
+			Policy:     hcsshim.Policy{Type: hcsshim.OutboundNat},
+			Exceptions: n.config.OutboundNatExceptions,
+		})
+
+		if err != nil {
+			return err
+		}
+		endpointStruct.Policies = append(endpointStruct.Policies, outboundNatPolicy)
+	}
+
 	configurationb, err := json.Marshal(endpointStruct)
 	if err != nil {
 		return err

+ 25 - 1
vendor/github.com/docker/libnetwork/iptables/iptables.go

@@ -276,7 +276,31 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
 		"--dport", strconv.Itoa(destPort),
 		"-j", "MASQUERADE",
 	}
-	return ProgramRule(Nat, "POSTROUTING", action, args)
+
+	if err := ProgramRule(Nat, "POSTROUTING", action, args); err != nil {
+		return err
+	}
+
+	if proto == "sctp" {
+		// Linux kernel v4.9 and below enables NETIF_F_SCTP_CRC for veth by
+		// the following commit.
+		// This introduces a problem when conbined with a physical NIC without
+		// NETIF_F_SCTP_CRC. As for a workaround, here we add an iptables entry
+		// to fill the checksum.
+		//
+		// https://github.com/torvalds/linux/commit/c80fafbbb59ef9924962f83aac85531039395b18
+		args = []string{
+			"-p", proto,
+			"--sport", strconv.Itoa(destPort),
+			"-j", "CHECKSUM",
+			"--checksum-fill",
+		}
+		if err := ProgramRule(Mangle, "POSTROUTING", action, args); err != nil {
+			return err
+		}
+	}
+
+	return nil
 }
 
 // Link adds reciprocal ACCEPT rule for two supplied IP addresses.

+ 4 - 3
vendor/github.com/docker/libnetwork/portallocator/portallocator.go

@@ -120,7 +120,7 @@ func (p *PortAllocator) RequestPortInRange(ip net.IP, proto string, portStart, p
 	p.mutex.Lock()
 	defer p.mutex.Unlock()
 
-	if proto != "tcp" && proto != "udp" {
+	if proto != "tcp" && proto != "udp" && proto != "sctp" {
 		return 0, ErrUnknownProtocol
 	}
 
@@ -131,8 +131,9 @@ func (p *PortAllocator) RequestPortInRange(ip net.IP, proto string, portStart, p
 	protomap, ok := p.ipMap[ipstr]
 	if !ok {
 		protomap = protoMap{
-			"tcp": p.newPortMap(),
-			"udp": p.newPortMap(),
+			"tcp":  p.newPortMap(),
+			"udp":  p.newPortMap(),
+			"sctp": p.newPortMap(),
 		}
 
 		p.ipMap[ipstr] = protomap

+ 56 - 3
vendor/github.com/docker/libnetwork/portmapper/mapper.go

@@ -8,6 +8,7 @@ import (
 
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/portallocator"
+	"github.com/ishidawataru/sctp"
 	"github.com/sirupsen/logrus"
 )
 
@@ -27,6 +28,8 @@ var (
 	ErrPortMappedForIP = errors.New("port is already mapped to ip")
 	// ErrPortNotMapped refers to an unmapped port
 	ErrPortNotMapped = errors.New("port is not mapped")
+	// ErrSCTPAddrNoIP refers to a SCTP address without IP address.
+	ErrSCTPAddrNoIP = errors.New("sctp address does not contain any IP address")
 )
 
 // PortMapper manages the network address translation
@@ -98,7 +101,10 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
 				return nil, err
 			}
 		} else {
-			m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
+			m.userlandProxy, err = newDummyProxy(proto, hostIP, allocatedHostPort)
+			if err != nil {
+				return nil, err
+			}
 		}
 	case *net.UDPAddr:
 		proto = "udp"
@@ -118,7 +124,37 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
 				return nil, err
 			}
 		} else {
-			m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
+			m.userlandProxy, err = newDummyProxy(proto, hostIP, allocatedHostPort)
+			if err != nil {
+				return nil, err
+			}
+		}
+	case *sctp.SCTPAddr:
+		proto = "sctp"
+		if allocatedHostPort, err = pm.Allocator.RequestPortInRange(hostIP, proto, hostPortStart, hostPortEnd); err != nil {
+			return nil, err
+		}
+
+		m = &mapping{
+			proto:     proto,
+			host:      &sctp.SCTPAddr{IP: []net.IP{hostIP}, Port: allocatedHostPort},
+			container: container,
+		}
+
+		if useProxy {
+			sctpAddr := container.(*sctp.SCTPAddr)
+			if len(sctpAddr.IP) == 0 {
+				return nil, ErrSCTPAddrNoIP
+			}
+			m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, sctpAddr.IP[0], sctpAddr.Port, pm.proxyPath)
+			if err != nil {
+				return nil, err
+			}
+		} else {
+			m.userlandProxy, err = newDummyProxy(proto, hostIP, allocatedHostPort)
+			if err != nil {
+				return nil, err
+			}
 		}
 	default:
 		return nil, ErrUnknownBackendAddressType
@@ -195,8 +231,13 @@ func (pm *PortMapper) Unmap(host net.Addr) error {
 		return pm.Allocator.ReleasePort(a.IP, "tcp", a.Port)
 	case *net.UDPAddr:
 		return pm.Allocator.ReleasePort(a.IP, "udp", a.Port)
+	case *sctp.SCTPAddr:
+		if len(a.IP) == 0 {
+			return ErrSCTPAddrNoIP
+		}
+		return pm.Allocator.ReleasePort(a.IP[0], "sctp", a.Port)
 	}
-	return nil
+	return ErrUnknownBackendAddressType
 }
 
 //ReMapAll will re-apply all port mappings
@@ -219,6 +260,12 @@ func getKey(a net.Addr) string {
 		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "tcp")
 	case *net.UDPAddr:
 		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
+	case *sctp.SCTPAddr:
+		if len(t.IP) == 0 {
+			logrus.Error(ErrSCTPAddrNoIP)
+			return ""
+		}
+		return fmt.Sprintf("%s:%d/%s", t.IP[0].String(), t.Port, "sctp")
 	}
 	return ""
 }
@@ -229,6 +276,12 @@ func getIPAndPort(a net.Addr) (net.IP, int) {
 		return t.IP, t.Port
 	case *net.UDPAddr:
 		return t.IP, t.Port
+	case *sctp.SCTPAddr:
+		if len(t.IP) == 0 {
+			logrus.Error(ErrSCTPAddrNoIP)
+			return nil, 0
+		}
+		return t.IP[0], t.Port
 	}
 	return nil, 0
 }

+ 16 - 4
vendor/github.com/docker/libnetwork/portmapper/proxy.go

@@ -8,6 +8,8 @@ import (
 	"os"
 	"os/exec"
 	"time"
+
+	"github.com/ishidawataru/sctp"
 )
 
 var userlandProxyCommandName = "docker-proxy"
@@ -79,16 +81,20 @@ type dummyProxy struct {
 	addr     net.Addr
 }
 
-func newDummyProxy(proto string, hostIP net.IP, hostPort int) userlandProxy {
+func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, error) {
 	switch proto {
 	case "tcp":
 		addr := &net.TCPAddr{IP: hostIP, Port: hostPort}
-		return &dummyProxy{addr: addr}
+		return &dummyProxy{addr: addr}, nil
 	case "udp":
 		addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
-		return &dummyProxy{addr: addr}
+		return &dummyProxy{addr: addr}, nil
+	case "sctp":
+		addr := &sctp.SCTPAddr{IP: []net.IP{hostIP}, Port: hostPort}
+		return &dummyProxy{addr: addr}, nil
+	default:
+		return nil, fmt.Errorf("Unknown addr type: %s", proto)
 	}
-	return nil
 }
 
 func (p *dummyProxy) Start() error {
@@ -105,6 +111,12 @@ func (p *dummyProxy) Start() error {
 			return err
 		}
 		p.listener = l
+	case *sctp.SCTPAddr:
+		l, err := sctp.ListenSCTP("sctp", addr)
+		if err != nil {
+			return err
+		}
+		p.listener = l
 	default:
 		return fmt.Errorf("Unknown addr type: %T", p.addr)
 	}

+ 6 - 0
vendor/github.com/docker/libnetwork/service_linux.go

@@ -19,6 +19,7 @@ import (
 	"github.com/docker/libnetwork/ipvs"
 	"github.com/docker/libnetwork/ns"
 	"github.com/gogo/protobuf/proto"
+	"github.com/ishidawataru/sctp"
 	"github.com/sirupsen/logrus"
 	"github.com/vishvananda/netlink/nl"
 	"github.com/vishvananda/netns"
@@ -503,6 +504,10 @@ func plumbProxy(iPort *PortConfig, isDelete bool) error {
 		l, err = net.ListenTCP("tcp", &net.TCPAddr{Port: int(iPort.PublishedPort)})
 	case ProtocolUDP:
 		l, err = net.ListenUDP("udp", &net.UDPAddr{Port: int(iPort.PublishedPort)})
+	case ProtocolSCTP:
+		l, err = sctp.ListenSCTP("sctp", &sctp.SCTPAddr{Port: int(iPort.PublishedPort)})
+	default:
+		err = fmt.Errorf("unknown protocol %v", iPort.Protocol)
 	}
 
 	if err != nil {
@@ -761,6 +766,7 @@ func redirecter() {
 
 	// Ensure blocking rules for anything else in/to ingress network
 	for _, rule := range [][]string{
+		{"-d", eIP.String(), "-p", "sctp", "-j", "DROP"},
 		{"-d", eIP.String(), "-p", "udp", "-j", "DROP"},
 		{"-d", eIP.String(), "-p", "tcp", "-j", "DROP"},
 	} {

+ 12 - 0
vendor/github.com/docker/libnetwork/types/types.go

@@ -7,6 +7,8 @@ import (
 	"net"
 	"strconv"
 	"strings"
+
+	"github.com/ishidawataru/sctp"
 )
 
 // constants for the IP address type
@@ -96,6 +98,8 @@ func (p PortBinding) HostAddr() (net.Addr, error) {
 		return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
 	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
 	default:
 		return nil, ErrInvalidProtocolBinding(p.Proto.String())
 	}
@@ -108,6 +112,8 @@ func (p PortBinding) ContainerAddr() (net.Addr, error) {
 		return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil
 	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
 	default:
 		return nil, ErrInvalidProtocolBinding(p.Proto.String())
 	}
@@ -233,6 +239,8 @@ const (
 	TCP = 6
 	// UDP is for the UDP ip protocol
 	UDP = 17
+	// SCTP is for the SCTP ip protocol
+	SCTP = 132
 )
 
 // Protocol represents an IP protocol number
@@ -246,6 +254,8 @@ func (p Protocol) String() string {
 		return "tcp"
 	case UDP:
 		return "udp"
+	case SCTP:
+		return "sctp"
 	default:
 		return fmt.Sprintf("%d", p)
 	}
@@ -260,6 +270,8 @@ func ParseProtocol(s string) Protocol {
 		return UDP
 	case "tcp":
 		return TCP
+	case "sctp":
+		return SCTP
 	default:
 		return 0
 	}

+ 1 - 0
vendor/github.com/docker/libnetwork/vendor.conf

@@ -51,3 +51,4 @@ golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
 golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
 github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
+github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb

+ 201 - 0
vendor/github.com/ishidawataru/sctp/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 18 - 0
vendor/github.com/ishidawataru/sctp/README.md

@@ -0,0 +1,18 @@
+Stream Control Transmission Protocol (SCTP)
+----
+
+[![Build Status](https://travis-ci.org/ishidawataru/sctp.svg?branch=master)](https://travis-ci.org/ishidawataru/sctp/builds)
+
+Examples
+----
+
+See `example/sctp.go`
+
+```go
+$ cd example
+$ go build
+$ # run example SCTP server
+$ ./example -server -port 1000 -ip 10.10.0.1,10.20.0.1
+$ # run example SCTP client
+$ ./example -port 1000 -ip 10.10.0.1,10.20.0.1
+```

+ 656 - 0
vendor/github.com/ishidawataru/sctp/sctp.go

@@ -0,0 +1,656 @@
+package sctp
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"net"
+	"strconv"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"syscall"
+	"time"
+	"unsafe"
+)
+
+const (
+	SOL_SCTP = 132
+
+	SCTP_BINDX_ADD_ADDR = 0x01
+	SCTP_BINDX_REM_ADDR = 0x02
+
+	MSG_NOTIFICATION = 0x8000
+)
+
+const (
+	SCTP_RTOINFO = iota
+	SCTP_ASSOCINFO
+	SCTP_INITMSG
+	SCTP_NODELAY
+	SCTP_AUTOCLOSE
+	SCTP_SET_PEER_PRIMARY_ADDR
+	SCTP_PRIMARY_ADDR
+	SCTP_ADAPTATION_LAYER
+	SCTP_DISABLE_FRAGMENTS
+	SCTP_PEER_ADDR_PARAMS
+	SCTP_DEFAULT_SENT_PARAM
+	SCTP_EVENTS
+	SCTP_I_WANT_MAPPED_V4_ADDR
+	SCTP_MAXSEG
+	SCTP_STATUS
+	SCTP_GET_PEER_ADDR_INFO
+	SCTP_DELAYED_ACK_TIME
+	SCTP_DELAYED_ACK  = SCTP_DELAYED_ACK_TIME
+	SCTP_DELAYED_SACK = SCTP_DELAYED_ACK_TIME
+
+	SCTP_SOCKOPT_BINDX_ADD = 100
+	SCTP_SOCKOPT_BINDX_REM = 101
+	SCTP_SOCKOPT_PEELOFF   = 102
+	SCTP_GET_PEER_ADDRS    = 108
+	SCTP_GET_LOCAL_ADDRS   = 109
+	SCTP_SOCKOPT_CONNECTX  = 110
+	SCTP_SOCKOPT_CONNECTX3 = 111
+)
+
+const (
+	SCTP_EVENT_DATA_IO = 1 << iota
+	SCTP_EVENT_ASSOCIATION
+	SCTP_EVENT_ADDRESS
+	SCTP_EVENT_SEND_FAILURE
+	SCTP_EVENT_PEER_ERROR
+	SCTP_EVENT_SHUTDOWN
+	SCTP_EVENT_PARTIAL_DELIVERY
+	SCTP_EVENT_ADAPTATION_LAYER
+	SCTP_EVENT_AUTHENTICATION
+	SCTP_EVENT_SENDER_DRY
+
+	SCTP_EVENT_ALL = SCTP_EVENT_DATA_IO | SCTP_EVENT_ASSOCIATION | SCTP_EVENT_ADDRESS | SCTP_EVENT_SEND_FAILURE | SCTP_EVENT_PEER_ERROR | SCTP_EVENT_SHUTDOWN | SCTP_EVENT_PARTIAL_DELIVERY | SCTP_EVENT_ADAPTATION_LAYER | SCTP_EVENT_AUTHENTICATION | SCTP_EVENT_SENDER_DRY
+)
+
+type SCTPNotificationType int
+
+const (
+	SCTP_SN_TYPE_BASE = SCTPNotificationType(iota + (1 << 15))
+	SCTP_ASSOC_CHANGE
+	SCTP_PEER_ADDR_CHANGE
+	SCTP_SEND_FAILED
+	SCTP_REMOTE_ERROR
+	SCTP_SHUTDOWN_EVENT
+	SCTP_PARTIAL_DELIVERY_EVENT
+	SCTP_ADAPTATION_INDICATION
+	SCTP_AUTHENTICATION_INDICATION
+	SCTP_SENDER_DRY_EVENT
+)
+
+type NotificationHandler func([]byte) error
+
+type EventSubscribe struct {
+	DataIO          uint8
+	Association     uint8
+	Address         uint8
+	SendFailure     uint8
+	PeerError       uint8
+	Shutdown        uint8
+	PartialDelivery uint8
+	AdaptationLayer uint8
+	Authentication  uint8
+	SenderDry       uint8
+}
+
+const (
+	SCTP_CMSG_INIT = iota
+	SCTP_CMSG_SNDRCV
+	SCTP_CMSG_SNDINFO
+	SCTP_CMSG_RCVINFO
+	SCTP_CMSG_NXTINFO
+)
+
+const (
+	SCTP_UNORDERED = 1 << iota
+	SCTP_ADDR_OVER
+	SCTP_ABORT
+	SCTP_SACK_IMMEDIATELY
+	SCTP_EOF
+)
+
+const (
+	SCTP_MAX_STREAM = 0xffff
+)
+
+type InitMsg struct {
+	NumOstreams    uint16
+	MaxInstreams   uint16
+	MaxAttempts    uint16
+	MaxInitTimeout uint16
+}
+
+type SndRcvInfo struct {
+	Stream  uint16
+	SSN     uint16
+	Flags   uint16
+	_       uint16
+	PPID    uint32
+	Context uint32
+	TTL     uint32
+	TSN     uint32
+	CumTSN  uint32
+	AssocID int32
+}
+
+type SndInfo struct {
+	SID     uint16
+	Flags   uint16
+	PPID    uint32
+	Context uint32
+	AssocID int32
+}
+
+type GetAddrsOld struct {
+	AssocID int32
+	AddrNum int32
+	Addrs   uintptr
+}
+
+type NotificationHeader struct {
+	Type   uint16
+	Flags  uint16
+	Length uint32
+}
+
+type SCTPState uint16
+
+const (
+	SCTP_COMM_UP = SCTPState(iota)
+	SCTP_COMM_LOST
+	SCTP_RESTART
+	SCTP_SHUTDOWN_COMP
+	SCTP_CANT_STR_ASSOC
+)
+
+var nativeEndian binary.ByteOrder
+var sndRcvInfoSize uintptr
+
+func init() {
+	i := uint16(1)
+	if *(*byte)(unsafe.Pointer(&i)) == 0 {
+		nativeEndian = binary.BigEndian
+	} else {
+		nativeEndian = binary.LittleEndian
+	}
+	info := SndRcvInfo{}
+	sndRcvInfoSize = unsafe.Sizeof(info)
+}
+
+func toBuf(v interface{}) []byte {
+	var buf bytes.Buffer
+	binary.Write(&buf, nativeEndian, v)
+	return buf.Bytes()
+}
+
+func htons(h uint16) uint16 {
+	if nativeEndian == binary.LittleEndian {
+		return (h << 8 & 0xff00) | (h >> 8 & 0xff)
+	}
+	return h
+}
+
+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))
+	return err
+}
+
+type SCTPAddr struct {
+	IP   []net.IP
+	Port int
+}
+
+func (a *SCTPAddr) ToRawSockAddrBuf() []byte {
+	buf := []byte{}
+	p := htons(uint16(a.Port))
+	for _, ip := range a.IP {
+		if ip.To4() != nil {
+			s := syscall.RawSockaddrInet4{
+				Family: syscall.AF_INET,
+				Port:   p,
+			}
+			copy(s.Addr[:], ip.To4())
+			buf = append(buf, toBuf(s)...)
+		} else {
+			s := syscall.RawSockaddrInet6{
+				Family: syscall.AF_INET6,
+				Port:   p,
+			}
+			copy(s.Addr[:], ip)
+			buf = append(buf, toBuf(s)...)
+		}
+	}
+	return buf
+}
+
+func (a *SCTPAddr) String() string {
+	var b bytes.Buffer
+
+	for n, i := range a.IP {
+		if a.IP[n].To4() != nil {
+			b.WriteString(i.String())
+		} else if a.IP[n].To16() != nil {
+			b.WriteRune('[')
+			b.WriteString(i.String())
+			b.WriteRune(']')
+		}
+		if n < len(a.IP)-1 {
+			b.WriteRune('/')
+		}
+	}
+	b.WriteRune(':')
+	b.WriteString(strconv.Itoa(a.Port))
+	return b.String()
+}
+
+func (a *SCTPAddr) Network() string { return "sctp" }
+
+func ResolveSCTPAddr(network, addrs string) (*SCTPAddr, error) {
+	tcpnet := ""
+	switch network {
+	case "", "sctp":
+	case "sctp4":
+		tcpnet = "tcp4"
+	case "sctp6":
+		tcpnet = "tcp6"
+	default:
+		return nil, fmt.Errorf("invalid net: %s", network)
+	}
+	elems := strings.Split(addrs, "/")
+	if len(elems) == 0 {
+		return nil, fmt.Errorf("invalid input: %s", addrs)
+	}
+	ipaddrs := make([]net.IP, 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)
+	}
+	tcpa, err := net.ResolveTCPAddr(tcpnet, elems[len(elems)-1])
+	if err != nil {
+		return nil, err
+	}
+	if tcpa.IP != nil {
+		ipaddrs = append(ipaddrs, tcpa.IP)
+	} else {
+		ipaddrs = nil
+	}
+	return &SCTPAddr{
+		IP:   ipaddrs,
+		Port: tcpa.Port,
+	}, nil
+}
+
+func SCTPConnect(fd int, addr *SCTPAddr) (int, error) {
+	buf := addr.ToRawSockAddrBuf()
+	param := GetAddrsOld{
+		AddrNum: int32(len(buf)),
+		Addrs:   uintptr(uintptr(unsafe.Pointer(&buf[0]))),
+	}
+	optlen := unsafe.Sizeof(param)
+	_, _, err := getsockopt(fd, SCTP_SOCKOPT_CONNECTX3, uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
+	if err == nil {
+		return int(param.AssocID), nil
+	} else if err != syscall.ENOPROTOOPT {
+		return 0, err
+	}
+	r0, _, err := setsockopt(fd, SCTP_SOCKOPT_CONNECTX, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
+	return int(r0), err
+}
+
+func SCTPBind(fd int, addr *SCTPAddr, flags int) error {
+	var option uintptr
+	switch flags {
+	case SCTP_BINDX_ADD_ADDR:
+		option = SCTP_SOCKOPT_BINDX_ADD
+	case SCTP_BINDX_REM_ADDR:
+		option = SCTP_SOCKOPT_BINDX_REM
+	default:
+		return syscall.EINVAL
+	}
+
+	buf := addr.ToRawSockAddrBuf()
+	_, _, err := setsockopt(fd, option, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
+	return err
+}
+
+type SCTPConn struct {
+	_fd                 int32
+	notificationHandler NotificationHandler
+}
+
+func (c *SCTPConn) fd() int {
+	return int(atomic.LoadInt32(&c._fd))
+}
+
+func NewSCTPConn(fd int, handler NotificationHandler) *SCTPConn {
+	conn := &SCTPConn{
+		_fd:                 int32(fd),
+		notificationHandler: handler,
+	}
+	return conn
+}
+
+func (c *SCTPConn) Write(b []byte) (int, error) {
+	return c.SCTPWrite(b, nil)
+}
+
+func (c *SCTPConn) Read(b []byte) (int, error) {
+	n, _, err := c.SCTPRead(b)
+	if n < 0 {
+		n = 0
+	}
+	return n, err
+}
+
+func (c *SCTPConn) SetInitMsg(numOstreams, maxInstreams, maxAttempts, maxInitTimeout int) error {
+	param := 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 {
+	var d, a, ad, sf, p, sh, pa, ada, au, se uint8
+	if flags&SCTP_EVENT_DATA_IO > 0 {
+		d = 1
+	}
+	if flags&SCTP_EVENT_ASSOCIATION > 0 {
+		a = 1
+	}
+	if flags&SCTP_EVENT_ADDRESS > 0 {
+		ad = 1
+	}
+	if flags&SCTP_EVENT_SEND_FAILURE > 0 {
+		sf = 1
+	}
+	if flags&SCTP_EVENT_PEER_ERROR > 0 {
+		p = 1
+	}
+	if flags&SCTP_EVENT_SHUTDOWN > 0 {
+		sh = 1
+	}
+	if flags&SCTP_EVENT_PARTIAL_DELIVERY > 0 {
+		pa = 1
+	}
+	if flags&SCTP_EVENT_ADAPTATION_LAYER > 0 {
+		ada = 1
+	}
+	if flags&SCTP_EVENT_AUTHENTICATION > 0 {
+		au = 1
+	}
+	if flags&SCTP_EVENT_SENDER_DRY > 0 {
+		se = 1
+	}
+	param := EventSubscribe{
+		DataIO:          d,
+		Association:     a,
+		Address:         ad,
+		SendFailure:     sf,
+		PeerError:       p,
+		Shutdown:        sh,
+		PartialDelivery: pa,
+		AdaptationLayer: ada,
+		Authentication:  au,
+		SenderDry:       se,
+	}
+	optlen := unsafe.Sizeof(param)
+	_, _, err := setsockopt(c.fd(), SCTP_EVENTS, uintptr(unsafe.Pointer(&param)), uintptr(optlen))
+	return err
+}
+
+func (c *SCTPConn) SubscribedEvents() (int, error) {
+	param := EventSubscribe{}
+	optlen := unsafe.Sizeof(param)
+	_, _, err := getsockopt(c.fd(), SCTP_EVENTS, uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
+	if err != nil {
+		return 0, err
+	}
+	var flags int
+	if param.DataIO > 0 {
+		flags |= SCTP_EVENT_DATA_IO
+	}
+	if param.Association > 0 {
+		flags |= SCTP_EVENT_ASSOCIATION
+	}
+	if param.Address > 0 {
+		flags |= SCTP_EVENT_ADDRESS
+	}
+	if param.SendFailure > 0 {
+		flags |= SCTP_EVENT_SEND_FAILURE
+	}
+	if param.PeerError > 0 {
+		flags |= SCTP_EVENT_PEER_ERROR
+	}
+	if param.Shutdown > 0 {
+		flags |= SCTP_EVENT_SHUTDOWN
+	}
+	if param.PartialDelivery > 0 {
+		flags |= SCTP_EVENT_PARTIAL_DELIVERY
+	}
+	if param.AdaptationLayer > 0 {
+		flags |= SCTP_EVENT_ADAPTATION_LAYER
+	}
+	if param.Authentication > 0 {
+		flags |= SCTP_EVENT_AUTHENTICATION
+	}
+	if param.SenderDry > 0 {
+		flags |= SCTP_EVENT_SENDER_DRY
+	}
+	return flags, nil
+}
+
+func (c *SCTPConn) SetDefaultSentParam(info *SndRcvInfo) error {
+	optlen := unsafe.Sizeof(*info)
+	_, _, err := setsockopt(c.fd(), SCTP_DEFAULT_SENT_PARAM, uintptr(unsafe.Pointer(info)), uintptr(optlen))
+	return err
+}
+
+func (c *SCTPConn) GetDefaultSentParam() (*SndRcvInfo, error) {
+	info := &SndRcvInfo{}
+	optlen := unsafe.Sizeof(*info)
+	_, _, err := getsockopt(c.fd(), SCTP_DEFAULT_SENT_PARAM, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(&optlen)))
+	return info, err
+}
+
+func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
+	addr := &SCTPAddr{
+		IP: make([]net.IP, n),
+	}
+
+	switch family := (*(*syscall.RawSockaddrAny)(ptr)).Addr.Family; family {
+	case syscall.AF_INET:
+		addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port)))
+		tmp := syscall.RawSockaddrInet4{}
+		size := unsafe.Sizeof(tmp)
+		for i := 0; i < n; i++ {
+			a := *(*syscall.RawSockaddrInet4)(unsafe.Pointer(
+				uintptr(ptr) + size*uintptr(i)))
+			addr.IP[i] = a.Addr[:]
+		}
+	case syscall.AF_INET6:
+		addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port)))
+		tmp := syscall.RawSockaddrInet6{}
+		size := unsafe.Sizeof(tmp)
+		for i := 0; i < n; i++ {
+			a := *(*syscall.RawSockaddrInet6)(unsafe.Pointer(
+				uintptr(ptr) + size*uintptr(i)))
+			addr.IP[i] = a.Addr[:]
+		}
+	default:
+		return nil, fmt.Errorf("unknown address family: %d", family)
+	}
+	return addr, nil
+}
+
+func sctpGetAddrs(fd, id, optname int) (*SCTPAddr, error) {
+
+	type getaddrs struct {
+		assocId int32
+		addrNum uint32
+		addrs   [4096]byte
+	}
+	param := getaddrs{
+		assocId: int32(id),
+	}
+	optlen := unsafe.Sizeof(param)
+	_, _, err := getsockopt(fd, uintptr(optname), uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
+	if err != nil {
+		return nil, err
+	}
+	return resolveFromRawAddr(unsafe.Pointer(&param.addrs), int(param.addrNum))
+}
+
+func (c *SCTPConn) SCTPGetPrimaryPeerAddr() (*SCTPAddr, error) {
+
+	type sctpGetSetPrim struct {
+		assocId int32
+		addrs   [128]byte
+	}
+	param := sctpGetSetPrim{
+		assocId: int32(0),
+	}
+	optlen := unsafe.Sizeof(param)
+	_, _, err := getsockopt(c.fd(), SCTP_PRIMARY_ADDR, uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
+	if err != nil {
+		return nil, err
+	}
+	return resolveFromRawAddr(unsafe.Pointer(&param.addrs), 1)
+}
+
+func (c *SCTPConn) SCTPLocalAddr(id int) (*SCTPAddr, error) {
+	return sctpGetAddrs(c.fd(), id, SCTP_GET_LOCAL_ADDRS)
+}
+
+func (c *SCTPConn) SCTPRemoteAddr(id int) (*SCTPAddr, error) {
+	return sctpGetAddrs(c.fd(), id, SCTP_GET_PEER_ADDRS)
+}
+
+func (c *SCTPConn) LocalAddr() net.Addr {
+	addr, err := sctpGetAddrs(c.fd(), 0, SCTP_GET_LOCAL_ADDRS)
+	if err != nil {
+		return nil
+	}
+	return addr
+}
+
+func (c *SCTPConn) RemoteAddr() net.Addr {
+	addr, err := sctpGetAddrs(c.fd(), 0, SCTP_GET_PEER_ADDRS)
+	if err != nil {
+		return nil
+	}
+	return addr
+}
+
+func (c *SCTPConn) PeelOff(id int) (*SCTPConn, error) {
+	type peeloffArg struct {
+		assocId int32
+		sd      int
+	}
+	param := peeloffArg{
+		assocId: int32(id),
+	}
+	optlen := unsafe.Sizeof(param)
+	_, _, err := getsockopt(c.fd(), SCTP_SOCKOPT_PEELOFF, uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
+	if err != nil {
+		return nil, err
+	}
+	return &SCTPConn{_fd: int32(param.sd)}, nil
+}
+
+func (c *SCTPConn) SetDeadline(t time.Time) error {
+	return syscall.EOPNOTSUPP
+}
+
+func (c *SCTPConn) SetReadDeadline(t time.Time) error {
+	return syscall.EOPNOTSUPP
+}
+
+func (c *SCTPConn) SetWriteDeadline(t time.Time) error {
+	return syscall.EOPNOTSUPP
+}
+
+type SCTPListener struct {
+	fd int
+	m  sync.Mutex
+}
+
+func (ln *SCTPListener) Addr() net.Addr {
+	laddr, err := sctpGetAddrs(ln.fd, 0, SCTP_GET_LOCAL_ADDRS)
+	if err != nil {
+		return nil
+	}
+	return laddr
+}
+
+type SCTPSndRcvInfoWrappedConn struct {
+	conn *SCTPConn
+}
+
+func NewSCTPSndRcvInfoWrappedConn(conn *SCTPConn) *SCTPSndRcvInfoWrappedConn {
+	conn.SubscribeEvents(SCTP_EVENT_DATA_IO)
+	return &SCTPSndRcvInfoWrappedConn{conn}
+}
+
+func (c *SCTPSndRcvInfoWrappedConn) Write(b []byte) (int, error) {
+	if len(b) < int(sndRcvInfoSize) {
+		return 0, syscall.EINVAL
+	}
+	info := (*SndRcvInfo)(unsafe.Pointer(&b[0]))
+	n, err := c.conn.SCTPWrite(b[sndRcvInfoSize:], info)
+	return n + int(sndRcvInfoSize), err
+}
+
+func (c *SCTPSndRcvInfoWrappedConn) Read(b []byte) (int, error) {
+	if len(b) < int(sndRcvInfoSize) {
+		return 0, syscall.EINVAL
+	}
+	n, info, err := c.conn.SCTPRead(b[sndRcvInfoSize:])
+	if err != nil {
+		return n, err
+	}
+	copy(b, toBuf(info))
+	return n + int(sndRcvInfoSize), err
+}
+
+func (c *SCTPSndRcvInfoWrappedConn) Close() error {
+	return c.conn.Close()
+}
+
+func (c *SCTPSndRcvInfoWrappedConn) LocalAddr() net.Addr {
+	return c.conn.LocalAddr()
+}
+
+func (c *SCTPSndRcvInfoWrappedConn) RemoteAddr() net.Addr {
+	return c.conn.RemoteAddr()
+}
+
+func (c *SCTPSndRcvInfoWrappedConn) SetDeadline(t time.Time) error {
+	return c.conn.SetDeadline(t)
+}
+
+func (c *SCTPSndRcvInfoWrappedConn) SetReadDeadline(t time.Time) error {
+	return c.conn.SetReadDeadline(t)
+}
+
+func (c *SCTPSndRcvInfoWrappedConn) SetWriteDeadline(t time.Time) error {
+	return c.conn.SetWriteDeadline(t)
+}

+ 227 - 0
vendor/github.com/ishidawataru/sctp/sctp_linux.go

@@ -0,0 +1,227 @@
+// +build linux,!386
+
+package sctp
+
+import (
+	"fmt"
+	"io"
+	"net"
+	"sync/atomic"
+	"syscall"
+	"unsafe"
+)
+
+func setsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) {
+	// FIXME: syscall.SYS_SETSOCKOPT is undefined on 386
+	r0, r1, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT,
+		uintptr(fd),
+		SOL_SCTP,
+		optname,
+		optval,
+		optlen,
+		0)
+	if errno != 0 {
+		return r0, r1, errno
+	}
+	return r0, r1, nil
+}
+
+func getsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) {
+	// FIXME: syscall.SYS_GETSOCKOPT is undefined on 386
+	r0, r1, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT,
+		uintptr(fd),
+		SOL_SCTP,
+		optname,
+		optval,
+		optlen,
+		0)
+	if errno != 0 {
+		return r0, r1, errno
+	}
+	return r0, r1, nil
+}
+
+func (c *SCTPConn) SCTPWrite(b []byte, info *SndRcvInfo) (int, error) {
+	var cbuf []byte
+	if info != nil {
+		cmsgBuf := toBuf(info)
+		hdr := &syscall.Cmsghdr{
+			Level: syscall.IPPROTO_SCTP,
+			Type:  SCTP_CMSG_SNDRCV,
+		}
+
+		// bitwidth of hdr.Len is platform-specific,
+		// so we use hdr.SetLen() rather than directly setting hdr.Len
+		hdr.SetLen(syscall.CmsgSpace(len(cmsgBuf)))
+		cbuf = append(toBuf(hdr), cmsgBuf...)
+	}
+	return syscall.SendmsgN(c.fd(), b, cbuf, nil, 0)
+}
+
+func parseSndRcvInfo(b []byte) (*SndRcvInfo, error) {
+	msgs, err := syscall.ParseSocketControlMessage(b)
+	if err != nil {
+		return nil, err
+	}
+	for _, m := range msgs {
+		if m.Header.Level == syscall.IPPROTO_SCTP {
+			switch m.Header.Type {
+			case SCTP_CMSG_SNDRCV:
+				return (*SndRcvInfo)(unsafe.Pointer(&m.Data[0])), nil
+			}
+		}
+	}
+	return nil, nil
+}
+
+func (c *SCTPConn) SCTPRead(b []byte) (int, *SndRcvInfo, error) {
+	oob := make([]byte, 254)
+	for {
+		n, oobn, recvflags, _, err := syscall.Recvmsg(c.fd(), b, oob, 0)
+		if err != nil {
+			return n, nil, err
+		}
+
+		if n == 0 && oobn == 0 {
+			return 0, nil, io.EOF
+		}
+
+		if recvflags&MSG_NOTIFICATION > 0 && c.notificationHandler != nil {
+			if err := c.notificationHandler(b[:n]); err != nil {
+				return 0, nil, err
+			}
+		} else {
+			var info *SndRcvInfo
+			if oobn > 0 {
+				info, err = parseSndRcvInfo(oob[:oobn])
+			}
+			return n, info, err
+		}
+	}
+}
+
+func (c *SCTPConn) Close() error {
+	if c != nil {
+		fd := atomic.SwapInt32(&c._fd, -1)
+		if fd > 0 {
+			info := &SndRcvInfo{
+				Flags: SCTP_EOF,
+			}
+			c.SCTPWrite(nil, info)
+			syscall.Shutdown(int(fd), syscall.SHUT_RDWR)
+			return syscall.Close(int(fd))
+		}
+	}
+	return syscall.EBADF
+}
+
+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)
+	}
+
+	sock, err := syscall.Socket(
+		af,
+		syscall.SOCK_STREAM,
+		syscall.IPPROTO_SCTP,
+	)
+	if err != nil {
+		return nil, err
+	}
+	err = setNumOstreams(sock, SCTP_MAX_STREAM)
+	if err != nil {
+		return nil, err
+	}
+	if laddr != nil && len(laddr.IP) != 0 {
+		err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
+		if err != nil {
+			return nil, err
+		}
+	}
+	err = syscall.Listen(sock, syscall.SOMAXCONN)
+	if err != nil {
+		return nil, err
+	}
+	return &SCTPListener{
+		fd: sock,
+	}, nil
+}
+
+func (ln *SCTPListener) Accept() (net.Conn, error) {
+	fd, _, err := syscall.Accept4(ln.fd, 0)
+	return NewSCTPConn(fd, nil), err
+}
+
+func (ln *SCTPListener) Close() error {
+	syscall.Shutdown(ln.fd, syscall.SHUT_RDWR)
+	return syscall.Close(ln.fd)
+}
+
+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)
+	}
+	sock, err := syscall.Socket(
+		af,
+		syscall.SOCK_STREAM,
+		syscall.IPPROTO_SCTP,
+	)
+	if err != nil {
+		return nil, err
+	}
+	err = setNumOstreams(sock, SCTP_MAX_STREAM)
+	if err != nil {
+		return nil, err
+	}
+	if laddr != nil {
+		err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
+		if err != nil {
+			return nil, err
+		}
+	}
+	_, err = SCTPConnect(sock, raddr)
+	if err != nil {
+		return nil, err
+	}
+	return NewSCTPConn(sock, nil), nil
+}

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

@@ -0,0 +1,47 @@
+// +build !linux linux,386
+
+package sctp
+
+import (
+	"errors"
+	"net"
+	"runtime"
+)
+
+var ErrUnsupported = errors.New("SCTP is unsupported on " + runtime.GOOS + "/" + runtime.GOARCH)
+
+func setsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) {
+	return 0, 0, ErrUnsupported
+}
+
+func getsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) {
+	return 0, 0, ErrUnsupported
+}
+
+func (c *SCTPConn) SCTPWrite(b []byte, info *SndRcvInfo) (int, error) {
+	return 0, ErrUnsupported
+}
+
+func (c *SCTPConn) SCTPRead(b []byte) (int, *SndRcvInfo, error) {
+	return 0, nil, ErrUnsupported
+}
+
+func (c *SCTPConn) Close() error {
+	return ErrUnsupported
+}
+
+func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
+	return nil, ErrUnsupported
+}
+
+func (ln *SCTPListener) Accept() (net.Conn, error) {
+	return nil, ErrUnsupported
+}
+
+func (ln *SCTPListener) Close() error {
+	return ErrUnsupported
+}
+
+func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) {
+	return nil, ErrUnsupported
+}