ソースを参照

go.net/ipv6: implement each platform's sticky socket option binding table

Also adds helper methods for platform-dependent types.

LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/165920044
Mikio Hara 11 年 前
コミット
235e882169
7 ファイル変更164 行追加124 行削除
  1. 0 23
      ipv6/sys.go
  2. 30 19
      ipv6/sys_bsd.go
  3. 54 26
      ipv6/sys_darwin.go
  4. 28 17
      ipv6/sys_linux.go
  5. 13 0
      ipv6/sys_stub.go
  6. 0 26
      ipv6/sys_unix.go
  7. 39 13
      ipv6/sys_windows.go

+ 0 - 23
ipv6/sys.go

@@ -1,23 +0,0 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ipv6
-
-type sysSockoptLen uint32
-
-const (
-	sysSizeofPacketInfo   = 0x14
-	sysSizeofMulticastReq = 0x14
-	sysSizeofICMPFilter   = 0x20
-)
-
-type sysPacketInfo struct {
-	IP      [16]byte
-	IfIndex uint32
-}
-
-type sysMulticastReq struct {
-	IP      [16]byte
-	IfIndex uint32
-}

+ 30 - 19
ipv6/sys_bsd.go

@@ -11,27 +11,38 @@ import (
 	"syscall"
 )
 
-// RFC 3542 options
-const (
-	// See /usr/include/netinet6/in6.h.
-	sysSockoptReceiveTrafficClass = syscall.IPV6_RECVTCLASS
-	sysSockoptTrafficClass        = syscall.IPV6_TCLASS
-	sysSockoptReceiveHopLimit     = syscall.IPV6_RECVHOPLIMIT
-	sysSockoptHopLimit            = syscall.IPV6_HOPLIMIT
-	sysSockoptReceivePacketInfo   = syscall.IPV6_RECVPKTINFO
-	sysSockoptPacketInfo          = syscall.IPV6_PKTINFO
-	sysSockoptReceivePathMTU      = syscall.IPV6_RECVPATHMTU
-	sysSockoptPathMTU             = syscall.IPV6_PATHMTU
-	sysSockoptNextHop             = syscall.IPV6_NEXTHOP
-	sysSockoptChecksum            = syscall.IPV6_CHECKSUM
-
-	// See /usr/include/netinet6/in6.h.
-	sysSockoptICMPFilter = 0x12 // syscall.ICMP6_FILTER
+type sysSockoptLen int32
+
+var (
+	sockOpts = [ssoMax]sockOpt{
+		ssoTrafficClass:        {ianaProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
+		ssoHopLimit:            {ianaProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
+		ssoMulticastInterface:  {ianaProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
+		ssoMulticastHopLimit:   {ianaProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
+		ssoMulticastLoopback:   {ianaProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
+		ssoReceiveTrafficClass: {ianaProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
+		ssoReceiveHopLimit:     {ianaProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
+		ssoReceivePacketInfo:   {ianaProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
+		ssoReceivePathMTU:      {ianaProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
+		ssoPathMTU:             {ianaProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
+		ssoChecksum:            {ianaProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
+		ssoICMPFilter:          {ianaProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
+		ssoJoinGroup:           {ianaProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq},
+		ssoLeaveGroup:          {ianaProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq},
+	}
 )
 
-func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
-	sa.Len = syscall.SizeofSockaddrInet6
+func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
+	sa.Len = sysSizeofSockaddrInet6
 	sa.Family = syscall.AF_INET6
 	copy(sa.Addr[:], ip)
-	sa.Scope_id = uint32(ifindex)
+	sa.Scope_id = uint32(i)
+}
+
+func (pi *sysInet6Pktinfo) setIfindex(i int) {
+	pi.Ifindex = uint32(i)
+}
+
+func (mreq *sysIPv6Mreq) setIfindex(i int) {
+	mreq.Interface = uint32(i)
 }

+ 54 - 26
ipv6/sys_darwin.go

@@ -9,35 +9,63 @@ import (
 	"syscall"
 )
 
-// RFC 2292 options
-const (
-	// See /usr/include/netinet6/in6.h.
-	sysSockopt2292HopLimit   = syscall.IPV6_2292HOPLIMIT
-	sysSockopt2292PacketInfo = syscall.IPV6_2292PKTINFO
-	sysSockopt2292NextHop    = syscall.IPV6_2292NEXTHOP
-)
+type sysSockoptLen int32
 
-// RFC 3542 options
-const (
-	// See /usr/include/netinet6/in6.h.
-	sysSockoptReceiveTrafficClass = 0x23 // IPV6_RECVTCLASS
-	sysSockoptTrafficClass        = 0x24 // IPV6_TCLASS
-	sysSockoptReceiveHopLimit     = 0x25 // IPV6_RECVHOPLIMIT
-	sysSockoptHopLimit            = 0x2f // IPV6_HOPLIMIT
-	sysSockoptReceivePacketInfo   = 0x3d // IPV6_RECVPKTINFO
-	sysSockoptPacketInfo          = 0x2e // IPV6_PKTINFO
-	sysSockoptReceivePathMTU      = 0x2b // IPV6_RECVPATHMTU
-	sysSockoptPathMTU             = 0x2c // IPV6_PATHMTU
-	sysSockoptNextHop             = 0x30 // IPV6_NEXTHOP
-	sysSockoptChecksum            = 0x1a // IPV6_CHECKSUM
-
-	// See /usr/include/netinet6/in6.h.
-	sysSockoptICMPFilter = 0x12 // ICMP6_FILTER
+var (
+	sockOpts = [ssoMax]sockOpt{
+		ssoTrafficClass:       {ianaProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
+		ssoHopLimit:           {ianaProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
+		ssoMulticastInterface: {ianaProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
+		ssoMulticastHopLimit:  {ianaProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
+		ssoMulticastLoopback:  {ianaProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
+		ssoReceiveHopLimit:    {ianaProtocolIPv6, sysIPV6_2292HOPLIMIT, ssoTypeInt},
+		ssoReceivePacketInfo:  {ianaProtocolIPv6, sysIPV6_2292PKTINFO, ssoTypeInt},
+		ssoChecksum:           {ianaProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
+		ssoICMPFilter:         {ianaProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
+		ssoJoinGroup:          {ianaProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq},
+		ssoLeaveGroup:         {ianaProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq},
+	}
 )
 
-func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
-	sa.Len = syscall.SizeofSockaddrInet6
+func init() {
+	// Seems like kern.osreldate is veiled on latest OS X. We use
+	// kern.osrelease instead.
+	osver, err := syscall.Sysctl("kern.osrelease")
+	if err != nil {
+		return
+	}
+	var i int
+	for i = range osver {
+		if osver[i] != '.' {
+			continue
+		}
+	}
+	// The IPV6_RECVPATHMTU and IPV6_PATHMTU options were
+	// introduced in OS X 10.7 (Darwin 11.0.0).
+	// See http://support.apple.com/kb/HT1633.
+	if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '1' {
+		sockOpts[ssoReceivePathMTU].level = ianaProtocolIPv6
+		sockOpts[ssoReceivePathMTU].name = sysIPV6_RECVPATHMTU
+		sockOpts[ssoReceivePathMTU].typ = ssoTypeInt
+		// Please be informed that IPV6_PATHMTU option will be
+		// a cause of kernel crash on 10.9 and earlier.
+		//sockOpts[ssoPathMTU].level = ianaProtocolIPv6
+		//sockOpts[ssoPathMTU].name = sysIPV6_PATHMTU
+		//sockOpts[ssoPathMTU].typ = ssoTypeMTUInfo
+	}
+}
+
+func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
+	sa.Len = sysSizeofSockaddrInet6
 	sa.Family = syscall.AF_INET6
 	copy(sa.Addr[:], ip)
-	sa.Scope_id = uint32(ifindex)
+	sa.Scope_id = uint32(i)
+}
+
+func (pi *sysInet6Pktinfo) setIfindex(i int) {
+	pi.Ifindex = uint32(i)
+}
+
+func (mreq *sysIPv6Mreq) setIfindex(i int) {
+	mreq.Interface = uint32(i)
 }

+ 28 - 17
ipv6/sys_linux.go

@@ -9,26 +9,37 @@ import (
 	"syscall"
 )
 
-// RFC 3542 options
-const (
-	// See /usr/include/linux/ipv6.h,in6.h.
-	sysSockoptReceiveTrafficClass = syscall.IPV6_RECVTCLASS
-	sysSockoptTrafficClass        = syscall.IPV6_TCLASS
-	sysSockoptReceiveHopLimit     = syscall.IPV6_RECVHOPLIMIT
-	sysSockoptHopLimit            = syscall.IPV6_HOPLIMIT
-	sysSockoptReceivePacketInfo   = syscall.IPV6_RECVPKTINFO
-	sysSockoptPacketInfo          = syscall.IPV6_PKTINFO
-	sysSockoptReceivePathMTU      = 0x3c // IPV6_RECVPATHMTU
-	sysSockoptPathMTU             = 0x3d // IPV6_PATHMTU
-	sysSockoptNextHop             = syscall.IPV6_NEXTHOP
-	sysSockoptChecksum            = syscall.IPV6_CHECKSUM
+type sysSockoptLen int32
 
-	// See /usr/include/linux/icmpv6.h.
-	sysSockoptICMPFilter = 0x1 // syscall.ICMPV6_FILTER
+var (
+	sockOpts = [ssoMax]sockOpt{
+		ssoTrafficClass:        {ianaProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
+		ssoHopLimit:            {ianaProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
+		ssoMulticastInterface:  {ianaProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
+		ssoMulticastHopLimit:   {ianaProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
+		ssoMulticastLoopback:   {ianaProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
+		ssoReceiveTrafficClass: {ianaProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
+		ssoReceiveHopLimit:     {ianaProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
+		ssoReceivePacketInfo:   {ianaProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
+		ssoReceivePathMTU:      {ianaProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
+		ssoPathMTU:             {ianaProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
+		ssoChecksum:            {ianaProtocolReserved, sysIPV6_CHECKSUM, ssoTypeInt},
+		ssoICMPFilter:          {ianaProtocolIPv6ICMP, sysICMPV6_FILTER, ssoTypeICMPFilter},
+		ssoJoinGroup:           {ianaProtocolIPv6, sysIPV6_ADD_MEMBERSHIP, ssoTypeIPMreq},
+		ssoLeaveGroup:          {ianaProtocolIPv6, sysIPV6_DROP_MEMBERSHIP, ssoTypeIPMreq},
+	}
 )
 
-func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
+func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
 	sa.Family = syscall.AF_INET6
 	copy(sa.Addr[:], ip)
-	sa.Scope_id = uint32(ifindex)
+	sa.Scope_id = uint32(i)
+}
+
+func (pi *sysInet6Pktinfo) setIfindex(i int) {
+	pi.Ifindex = int32(i)
+}
+
+func (mreq *sysIPv6Mreq) setIfindex(i int) {
+	mreq.Ifindex = int32(i)
 }

+ 13 - 0
ipv6/sys_stub.go

@@ -0,0 +1,13 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build nacl plan9 solaris
+
+package ipv6
+
+type sysSockoptLen int32
+
+var (
+	sockOpts = [ssoMax]sockOpt{}
+)

+ 0 - 26
ipv6/sys_unix.go

@@ -1,26 +0,0 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd
-
-package ipv6
-
-import "syscall"
-
-// RFC 3493 options
-const (
-	sysSockoptUnicastHopLimit    = syscall.IPV6_UNICAST_HOPS
-	sysSockoptMulticastHopLimit  = syscall.IPV6_MULTICAST_HOPS
-	sysSockoptMulticastInterface = syscall.IPV6_MULTICAST_IF
-	sysSockoptMulticastLoopback  = syscall.IPV6_MULTICAST_LOOP
-	sysSockoptJoinGroup          = syscall.IPV6_JOIN_GROUP
-	sysSockoptLeaveGroup         = syscall.IPV6_LEAVE_GROUP
-)
-
-const sysSizeofMTUInfo = 0x20
-
-type sysMTUInfo struct {
-	Addr syscall.RawSockaddrInet6
-	MTU  uint32
-}

+ 39 - 13
ipv6/sys_windows.go

@@ -9,25 +9,51 @@ import (
 	"syscall"
 )
 
-// RFC 3493 options
 const (
 	// See ws2tcpip.h.
-	sysSockoptUnicastHopLimit    = syscall.IPV6_UNICAST_HOPS
-	sysSockoptMulticastHopLimit  = syscall.IPV6_MULTICAST_HOPS
-	sysSockoptMulticastInterface = syscall.IPV6_MULTICAST_IF
-	sysSockoptMulticastLoopback  = syscall.IPV6_MULTICAST_LOOP
-	sysSockoptJoinGroup          = syscall.IPV6_JOIN_GROUP
-	sysSockoptLeaveGroup         = syscall.IPV6_LEAVE_GROUP
+	sysIPV6_UNICAST_HOPS   = 0x4
+	sysIPV6_MULTICAST_IF   = 0x9
+	sysIPV6_MULTICAST_HOPS = 0xa
+	sysIPV6_MULTICAST_LOOP = 0xb
+	sysIPV6_JOIN_GROUP     = 0xc
+	sysIPV6_LEAVE_GROUP    = 0xd
+	sysIPV6_PKTINFO        = 0x13
+
+	sysSizeofSockaddrInet6 = 0x1c
+
+	sysSizeofIPv6Mreq = 0x14
 )
 
-// RFC 3542 options
-const (
-	// See ws2tcpip.h.
-	sysSockoptPacketInfo = 0x13 // IPV6_PKTINFO
+type sysSockaddrInet6 struct {
+	Family   uint16
+	Port     uint16
+	Flowinfo uint32
+	Addr     [16]byte /* in6_addr */
+	Scope_id uint32
+}
+
+type sysIPv6Mreq struct {
+	Multiaddr [16]byte /* in6_addr */
+	Interface uint32
+}
+
+var (
+	sockOpts = [ssoMax]sockOpt{
+		ssoHopLimit:           {ianaProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
+		ssoMulticastInterface: {ianaProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
+		ssoMulticastHopLimit:  {ianaProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
+		ssoMulticastLoopback:  {ianaProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
+		ssoJoinGroup:          {ianaProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq},
+		ssoLeaveGroup:         {ianaProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq},
+	}
 )
 
-func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
+func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
 	sa.Family = syscall.AF_INET6
 	copy(sa.Addr[:], ip)
-	sa.Scope_id = uint32(ifindex)
+	sa.Scope_id = uint32(i)
+}
+
+func (mreq *sysIPv6Mreq) setIfindex(i int) {
+	mreq.Interface = uint32(i)
 }