Commit a7769702 authored by Mikio Hara's avatar Mikio Hara

ipv6: add support for solaris

This change adds support for Solaris.

To read and write IPv6 ancillary data using ControlMessage, ipv6 pacakge
requires https://go-review.googlesource.com/30171/

Note: Unlike other platforms, Solaris seems to have a few restrictions
on ICMP property access via raw IP sockets. At least applications are
prohibited from using IPV6_CHECKSUM option for ICMP transport.

Fixes golang/go#17324.

Change-Id: Ie014665d94ae6e4955c95d3eea88db90332e20bd
Reviewed-on: https://go-review.googlesource.com/30176
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent c8c327cf
......@@ -2,7 +2,7 @@
// 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
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv6
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build nacl plan9 solaris
// +build nacl plan9
package ipv6
......
......@@ -2,7 +2,7 @@
// 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
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv6
......
......@@ -9,6 +9,8 @@
package ipv6
/*
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
*/
......@@ -53,6 +55,13 @@ const (
sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS
sysMCAST_JOIN_GROUP = C.MCAST_JOIN_GROUP
sysMCAST_LEAVE_GROUP = C.MCAST_LEAVE_GROUP
sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE
sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE
sysMCAST_JOIN_SOURCE_GROUP = C.MCAST_JOIN_SOURCE_GROUP
sysMCAST_LEAVE_SOURCE_GROUP = C.MCAST_LEAVE_SOURCE_GROUP
sysIPV6_PREFER_SRC_HOME = C.IPV6_PREFER_SRC_HOME
sysIPV6_PREFER_SRC_COA = C.IPV6_PREFER_SRC_COA
sysIPV6_PREFER_SRC_PUBLIC = C.IPV6_PREFER_SRC_PUBLIC
......@@ -76,15 +85,20 @@ const (
sysICMP6_FILTER = C.ICMP6_FILTER
sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo
sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
sysSizeofGroupReq = C.sizeof_struct_group_req
sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req
sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
)
type sysSockaddrStorage C.struct_sockaddr_storage
type sysSockaddrInet6 C.struct_sockaddr_in6
type sysInet6Pktinfo C.struct_in6_pktinfo
......@@ -93,4 +107,8 @@ type sysIPv6Mtuinfo C.struct_ip6_mtuinfo
type sysIPv6Mreq C.struct_ipv6_mreq
type sysGroupReq C.struct_group_req
type sysGroupSourceReq C.struct_group_source_req
type sysICMPv6Filter C.struct_icmp6_filter
......@@ -2,7 +2,7 @@
// 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 windows
// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
package ipv6
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build nacl plan9 solaris
// +build nacl plan9
package ipv6
......
......@@ -2,7 +2,7 @@
// 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 windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package ipv6
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build nacl plan9 solaris
// +build nacl plan9
package ipv6
......
......@@ -7,18 +7,23 @@
package ipv6
func (f *sysICMPv6Filter) accept(typ ICMPType) {
// TODO(mikio): implement this
f.X__icmp6_filt[typ>>5] |= 1 << (uint32(typ) & 31)
}
func (f *sysICMPv6Filter) block(typ ICMPType) {
// TODO(mikio): implement this
f.X__icmp6_filt[typ>>5] &^= 1 << (uint32(typ) & 31)
}
func (f *sysICMPv6Filter) setAll(block bool) {
// TODO(mikio): implement this
for i := range f.X__icmp6_filt {
if block {
f.X__icmp6_filt[i] = 0
} else {
f.X__icmp6_filt[i] = 1<<32 - 1
}
}
}
func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool {
// TODO(mikio): implement this
return false
return f.X__icmp6_filt[typ>>5]&(1<<(uint32(typ)&31)) == 0
}
......@@ -34,7 +34,7 @@ func TestICMPString(t *testing.T) {
func TestICMPFilter(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
......@@ -61,7 +61,7 @@ func TestICMPFilter(t *testing.T) {
func TestSetICMPFilter(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......
......@@ -32,7 +32,7 @@ func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
case "freebsd": // due to a bug on loopback marking
// See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065.
t.Skipf("not supported on %s", runtime.GOOS)
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -132,7 +132,7 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
case "freebsd": // due to a bug on loopback marking
// See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065.
t.Skipf("not supported on %s", runtime.GOOS)
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -205,8 +205,12 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
if toggle {
psh = nil
if err := p.SetChecksum(true, 2); err != nil {
// Solaris never allows to
// modify ICMP properties.
if runtime.GOOS != "solaris" {
t.Fatal(err)
}
}
} else {
psh = pshicmp
// Some platforms never allow to
......
......@@ -22,7 +22,7 @@ var udpMultipleGroupListenerTests = []net.Addr{
func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -62,7 +62,7 @@ func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -114,7 +114,7 @@ func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {
func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -157,7 +157,7 @@ func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -201,7 +201,7 @@ func TestIPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "darwin", "dragonfly", "openbsd": // platforms that return fe80::1%lo0: bind: can't assign requested address
t.Skipf("not supported on %s", runtime.GOOS)
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......
......@@ -26,7 +26,7 @@ var packetConnMulticastSocketOptionTests = []struct {
func TestPacketConnMulticastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......
......@@ -102,7 +102,7 @@ func benchmarkReadWriteIPv6UDP(b *testing.B, p *ipv6.PacketConn, wb, rb []byte,
func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......
......@@ -2,7 +2,7 @@
// 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 windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package ipv6
......
......@@ -2,7 +2,7 @@
// 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 windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package ipv6
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !darwin,!freebsd,!linux
// +build !darwin,!freebsd,!linux,!solaris
package ipv6
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin freebsd linux
// +build darwin freebsd linux solaris
package ipv6
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build nacl plan9 solaris
// +build nacl plan9
package ipv6
......
......@@ -19,7 +19,7 @@ var supportsIPv6 bool = nettest.SupportsIPv6()
func TestConnInitiatorPathMTU(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -57,7 +57,7 @@ func TestConnInitiatorPathMTU(t *testing.T) {
func TestConnResponderPathMTU(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -95,7 +95,7 @@ func TestConnResponderPathMTU(t *testing.T) {
func TestPacketConnChecksum(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......
// Copyright 2016 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
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {sysIPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {sysIPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
ctlPacketInfo: {sysIPV6_PKTINFO, sysSizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
ctlNextHop: {sysIPV6_NEXTHOP, sysSizeofSockaddrInet6, marshalNextHop, parseNextHop},
ctlPathMTU: {sysIPV6_PATHMTU, sysSizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
sockOpts = [ssoMax]sockOpt{
ssoTrafficClass: {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
ssoReceivePathMTU: {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
ssoPathMTU: {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
ssoChecksum: {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
ssoJoinGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
ssoLeaveGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
ssoJoinSourceGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
}
)
func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
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)
}
func (gr *sysGroupReq) setGroup(grp net.IP) {
sa := (*sysSockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gr)) + 4))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sysSockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 4))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
sa = (*sysSockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 260))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
// Copyright 2016 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.
#include "textflag.h"
TEXT ·sysvicall6(SB),NOSPLIT,$0-88
JMP syscall·sysvicall6(SB)
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build nacl plan9 solaris
// +build nacl plan9
package ipv6
......
// Copyright 2016 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 solaris
package ipv6
import (
"syscall"
"unsafe"
)
//go:cgo_import_dynamic libc___xnet_getsockopt __xnet_getsockopt "libsocket.so"
//go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so"
//go:linkname procGetsockopt libc___xnet_getsockopt
//go:linkname procSetsockopt libc_setsockopt
var (
procGetsockopt uintptr
procSetsockopt uintptr
)
func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (uintptr, uintptr, syscall.Errno)
func getsockopt(s uintptr, level, name int, v unsafe.Pointer, l *uint32) error {
_, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procGetsockopt)), 5, s, uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0)
if errno != 0 {
return error(errno)
}
return nil
}
func setsockopt(s uintptr, level, name int, v unsafe.Pointer, l uint32) error {
if _, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procSetsockopt)), 5, s, uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
return error(errno)
}
return nil
}
......@@ -20,7 +20,7 @@ import (
func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -81,7 +81,7 @@ func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -127,8 +127,12 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
if toggle {
psh = nil
if err := p.SetChecksum(true, 2); err != nil {
// Solaris never allows to modify
// ICMP properties.
if runtime.GOOS != "solaris" {
t.Fatal(err)
}
}
} else {
psh = pshicmp
// Some platforms never allow to disable the
......
......@@ -16,7 +16,7 @@ import (
func TestConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......@@ -52,7 +52,7 @@ var packetConnUnicastSocketOptionTests = []struct {
func TestPacketConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
......
......@@ -44,6 +44,13 @@ const (
sysIPV6_RECVDSTOPTS = 0x28
sysMCAST_JOIN_GROUP = 0x29
sysMCAST_LEAVE_GROUP = 0x2a
sysMCAST_BLOCK_SOURCE = 0x2b
sysMCAST_UNBLOCK_SOURCE = 0x2c
sysMCAST_JOIN_SOURCE_GROUP = 0x2d
sysMCAST_LEAVE_SOURCE_GROUP = 0x2e
sysIPV6_PREFER_SRC_HOME = 0x1
sysIPV6_PREFER_SRC_COA = 0x2
sysIPV6_PREFER_SRC_PUBLIC = 0x4
......@@ -67,15 +74,25 @@ const (
sysICMP6_FILTER = 0x1
sysSizeofSockaddrStorage = 0x100
sysSizeofSockaddrInet6 = 0x20
sysSizeofInet6Pktinfo = 0x14
sysSizeofIPv6Mtuinfo = 0x24
sysSizeofIPv6Mreq = 0x14
sysSizeofGroupReq = 0x104
sysSizeofGroupSourceReq = 0x204
sysSizeofICMPv6Filter = 0x20
)
type sysSockaddrStorage struct {
Family uint16
X_ss_pad1 [6]int8
X_ss_align float64
X_ss_pad2 [240]int8
}
type sysSockaddrInet6 struct {
Family uint16
Port uint16
......@@ -100,6 +117,17 @@ type sysIPv6Mreq struct {
Interface uint32
}
type sysGroupReq struct {
Interface uint32
Pad_cgo_0 [256]byte
}
type sysGroupSourceReq struct {
Interface uint32
Pad_cgo_0 [256]byte
Pad_cgo_1 [256]byte
}
type sysICMPv6Filter struct {
X__icmp6_filt [8]uint32
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment