Commit c8c327cf authored by Mikio Hara's avatar Mikio Hara

ipv4: add support for solaris

This change adds support for Solaris.

To read and write IPv4 ancillary data using ControlMessage, ipv4 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 IP_RECVTTL option for ICMP transport.

Fixes golang/go#17323.

Change-Id: Icb6dfa3c8eced28d14693ddfea4601301999d735
Reviewed-on: https://go-review.googlesource.com/30175
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 ffe101cc
......@@ -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 linux
// +build darwin linux solaris
package ipv4
......
......@@ -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 ipv4
......
......@@ -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 ipv4
......
......@@ -9,6 +9,8 @@
package ipv4
/*
#include <sys/socket.h>
#include <netinet/in.h>
*/
import "C"
......@@ -25,14 +27,6 @@ const (
sysIP_RECVIF = C.IP_RECVIF
sysIP_RECVSLLA = C.IP_RECVSLLA
sysIP_RECVTTL = C.IP_RECVTTL
sysIP_NEXTHOP = C.IP_NEXTHOP
sysIP_PKTINFO = C.IP_PKTINFO
sysIP_RECVPKTINFO = C.IP_RECVPKTINFO
sysIP_DONTFRAG = C.IP_DONTFRAG
sysIP_BOUND_IF = C.IP_BOUND_IF
sysIP_UNSPEC_SRC = C.IP_UNSPEC_SRC
sysIP_BROADCAST_TTL = C.IP_BROADCAST_TTL
sysIP_DHCPINIT_IF = C.IP_DHCPINIT_IF
sysIP_MULTICAST_IF = C.IP_MULTICAST_IF
sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL
......@@ -43,15 +37,48 @@ const (
sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE
sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP
sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP
sysIP_NEXTHOP = C.IP_NEXTHOP
sysIP_PKTINFO = C.IP_PKTINFO
sysIP_RECVPKTINFO = C.IP_RECVPKTINFO
sysIP_DONTFRAG = C.IP_DONTFRAG
sysIP_BOUND_IF = C.IP_BOUND_IF
sysIP_UNSPEC_SRC = C.IP_UNSPEC_SRC
sysIP_BROADCAST_TTL = C.IP_BROADCAST_TTL
sysIP_DHCPINIT_IF = C.IP_DHCPINIT_IF
sysIP_REUSEADDR = C.IP_REUSEADDR
sysIP_DONTROUTE = C.IP_DONTROUTE
sysIP_BROADCAST = C.IP_BROADCAST
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
sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
sysSizeofSockaddrInet = C.sizeof_struct_sockaddr_in
sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo
sysSizeofIPMreq = C.sizeof_struct_ip_mreq
sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source
sysSizeofGroupReq = C.sizeof_struct_group_req
sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req
)
type sysSockaddrStorage C.struct_sockaddr_storage
type sysSockaddrInet C.struct_sockaddr_in
type sysInetPktinfo C.struct_in_pktinfo
type sysIPMreq C.struct_ip_mreq
type sysIPMreqSource C.struct_ip_mreq_source
type sysGroupReq C.struct_group_req
type sysGroupSourceReq C.struct_group_source_req
......@@ -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 ipv4
......
......@@ -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 ipv4
......
......@@ -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 ipv4
......
......@@ -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 ipv4
......
......@@ -166,7 +166,11 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
if _, err := p.MulticastLoopback(); err != nil {
t.Fatal(err)
}
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
cf := ipv4.FlagDst | ipv4.FlagInterface
if runtime.GOOS != "solaris" {
// Solaris never allows to modify ICMP properties.
cf |= ipv4.FlagTTL
}
for i, toggle := range []bool{true, false, true} {
wb, err := (&icmp.Message{
......
......@@ -21,7 +21,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 testing.Short() {
......@@ -61,7 +61,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 testing.Short() {
......@@ -113,7 +113,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 testing.Short() {
......@@ -156,7 +156,7 @@ func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
func TestIPSingleRawConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if testing.Short() {
......@@ -201,7 +201,7 @@ func TestIPSingleRawConnWithSingleGroupListener(t *testing.T) {
func TestIPPerInterfaceSingleRawConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if testing.Short() {
......
......@@ -26,7 +26,7 @@ var packetConnMulticastSocketOptionTests = []struct {
func TestPacketConnMulticastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
......@@ -66,7 +66,7 @@ var rawConnMulticastSocketOptionTests = []struct {
func TestRawConnMulticastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if m, ok := nettest.SupportsRawIPSocket(); !ok {
......
......@@ -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 !plan9,!solaris,!windows
// +build !plan9,!windows
package ipv4
......
......@@ -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 plan9 solaris windows
// +build plan9 windows
package ipv4
......
......@@ -91,7 +91,7 @@ func benchmarkReadWriteIPv4UDP(b *testing.B, p *ipv4.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)
}
......
......@@ -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 netbsd openbsd windows
// +build darwin dragonfly freebsd netbsd openbsd solaris windows
package ipv4
......
......@@ -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 netbsd openbsd windows
// +build darwin dragonfly freebsd netbsd openbsd solaris windows
package ipv4
......
......@@ -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,!netbsd,!openbsd,!windows
// +build !darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!windows
package ipv4
......
......@@ -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 ipv4
......
......@@ -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 ipv4
......
......@@ -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 ipv4
......
......@@ -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 ipv4
......
// 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 ipv4
import (
"net"
"syscall"
"unsafe"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTTL: {sysIP_RECVTTL, 4, marshalTTL, parseTTL},
ctlPacketInfo: {sysIP_PKTINFO, sysSizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
}
sockOpts = [ssoMax]sockOpt{
ssoTOS: {sysIP_TOS, ssoTypeInt},
ssoTTL: {sysIP_TTL, ssoTypeInt},
ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte},
ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeByte},
ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt},
ssoPacketInfo: {sysIP_RECVPKTINFO, ssoTypeInt},
ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt},
ssoJoinGroup: {sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
ssoLeaveGroup: {sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
ssoJoinSourceGroup: {sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
}
)
func (pi *sysInetPktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
func (gr *sysGroupReq) setGroup(grp net.IP) {
sa := (*sysSockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gr)) + 4))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
}
func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sysSockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 4))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
sa = (*sysSockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 260))
sa.Family = syscall.AF_INET
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 ipv4
......
// 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 ipv4
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)
}
ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
......@@ -74,7 +74,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 m, ok := nettest.SupportsRawIPSocket(); !ok {
......@@ -97,7 +97,11 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
}
p := ipv4.NewPacketConn(c)
defer p.Close()
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
cf := ipv4.FlagDst | ipv4.FlagInterface
if runtime.GOOS != "solaris" {
// Solaris never allows to modify ICMP properties.
cf |= ipv4.FlagTTL
}
for i, toggle := range []bool{true, false, true} {
wb, err := (&icmp.Message{
......@@ -156,7 +160,7 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
func TestRawConnReadWriteUnicastICMP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if m, ok := nettest.SupportsRawIPSocket(); !ok {
......
......@@ -16,7 +16,7 @@ import (
func TestConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
......@@ -53,7 +53,7 @@ var packetConnUnicastSocketOptionTests = []struct {
func TestPacketConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
......@@ -79,7 +79,7 @@ func TestPacketConnUnicastSocketOptions(t *testing.T) {
func TestRawConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if m, ok := nettest.SupportsRawIPSocket(); !ok {
......
......@@ -17,14 +17,6 @@ const (
sysIP_RECVIF = 0x9
sysIP_RECVSLLA = 0xa
sysIP_RECVTTL = 0xb
sysIP_NEXTHOP = 0x19
sysIP_PKTINFO = 0x1a
sysIP_RECVPKTINFO = 0x1a
sysIP_DONTFRAG = 0x1b
sysIP_BOUND_IF = 0x41
sysIP_UNSPEC_SRC = 0x42
sysIP_BROADCAST_TTL = 0x43
sysIP_DHCPINIT_IF = 0x45
sysIP_MULTICAST_IF = 0x10
sysIP_MULTICAST_TTL = 0x11
......@@ -35,13 +27,52 @@ const (
sysIP_UNBLOCK_SOURCE = 0x16
sysIP_ADD_SOURCE_MEMBERSHIP = 0x17
sysIP_DROP_SOURCE_MEMBERSHIP = 0x18
sysIP_NEXTHOP = 0x19
sysIP_PKTINFO = 0x1a
sysIP_RECVPKTINFO = 0x1a
sysIP_DONTFRAG = 0x1b
sysIP_BOUND_IF = 0x41
sysIP_UNSPEC_SRC = 0x42
sysIP_BROADCAST_TTL = 0x43
sysIP_DHCPINIT_IF = 0x45
sysIP_REUSEADDR = 0x104
sysIP_DONTROUTE = 0x105
sysIP_BROADCAST = 0x106
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
sysSizeofSockaddrStorage = 0x100
sysSizeofSockaddrInet = 0x10
sysSizeofInetPktinfo = 0xc
sysSizeofIPMreq = 0x8
sysSizeofIPMreqSource = 0xc
sysSizeofGroupReq = 0x104
sysSizeofGroupSourceReq = 0x204
)
type sysSockaddrStorage struct {
Family uint16
X_ss_pad1 [6]int8
X_ss_align float64
X_ss_pad2 [240]int8
}
type sysSockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type sysInetPktinfo struct {
Ifindex uint32
Spec_dst [4]byte /* in_addr */
......@@ -58,3 +89,14 @@ type sysIPMreqSource struct {
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
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
}
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