go.net/ipv4: add support for dragonfly, enable IP_PKTINFO on darwin

This CL adds support for dragonfly and IP_PKTINFO support for darwin
with less dependency on syscall package.

Update golang/go#7175
Fixes golang/go#7172.

LGTM=iant
R=golang-codereviews, gobot, iant
CC=golang-codereviews
https://golang.org/cl/97800043
This commit is contained in:
Mikio Hara
2014-05-19 12:20:11 +09:00
parent f572974747
commit 38dcae4017
32 changed files with 640 additions and 349 deletions

View File

@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin freebsd netbsd openbsd
// +build darwin dragonfly freebsd netbsd openbsd
package ipv4
import (
"net"
"os"
"syscall"
"unsafe"
)
@@ -26,62 +25,92 @@ func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
opt.clear(FlagTTL)
}
}
if cf&FlagDst != 0 {
if err := setIPv4ReceiveDestinationAddress(fd, on); err != nil {
return err
if supportsPacketInfo {
if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
if err := setIPv4PacketInfo(fd, on); err != nil {
return err
}
if on {
opt.set(cf & (FlagSrc | FlagDst | FlagInterface))
} else {
opt.clear(cf & (FlagSrc | FlagDst | FlagInterface))
}
}
if on {
opt.set(FlagDst)
} else {
opt.clear(FlagDst)
} else {
if cf&FlagDst != 0 {
if err := setIPv4ReceiveDestinationAddress(fd, on); err != nil {
return err
}
if on {
opt.set(FlagDst)
} else {
opt.clear(FlagDst)
}
}
}
if cf&FlagInterface != 0 {
if err := setIPv4ReceiveInterface(fd, on); err != nil {
return err
}
if on {
opt.set(FlagInterface)
} else {
opt.clear(FlagInterface)
if cf&FlagInterface != 0 {
if err := setIPv4ReceiveInterface(fd, on); err != nil {
return err
}
if on {
opt.set(FlagInterface)
} else {
opt.clear(FlagInterface)
}
}
}
return nil
}
func newControlMessage(opt *rawOpt) (oob []byte) {
opt.Lock()
defer opt.Unlock()
l, off := 0, 0
func (opt *rawOpt) oobLen() (l int) {
if opt.isset(FlagTTL) {
l += syscall.CmsgSpace(1)
}
if opt.isset(FlagDst) {
l += syscall.CmsgSpace(net.IPv4len)
if supportsPacketInfo {
if opt.isset(FlagSrc | FlagDst | FlagInterface) {
l += syscall.CmsgSpace(sysSizeofPacketInfo)
}
} else {
if opt.isset(FlagDst) {
l += syscall.CmsgSpace(net.IPv4len)
}
if opt.isset(FlagInterface) {
l += syscall.CmsgSpace(syscall.SizeofSockaddrDatalink)
}
}
if opt.isset(FlagInterface) {
l += syscall.CmsgSpace(syscall.SizeofSockaddrDatalink)
return
}
func (opt *rawOpt) marshalControlMessage() (oob []byte) {
var off int
oob = make([]byte, opt.oobLen())
if opt.isset(FlagTTL) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIP
m.Type = sysSockoptReceiveTTL
m.SetLen(syscall.CmsgLen(1))
off += syscall.CmsgSpace(1)
}
if l > 0 {
oob = make([]byte, l)
if opt.isset(FlagTTL) {
if supportsPacketInfo {
if opt.isset(FlagSrc | FlagDst | FlagInterface) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIP
m.Type = syscall.IP_RECVTTL
m.SetLen(syscall.CmsgLen(1))
off += syscall.CmsgSpace(1)
m.Type = sysSockoptPacketInfo
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
off += syscall.CmsgSpace(sysSizeofPacketInfo)
}
} else {
if opt.isset(FlagDst) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIP
m.Type = syscall.IP_RECVDSTADDR
m.Type = sysSockoptReceiveDst
m.SetLen(syscall.CmsgLen(net.IPv4len))
off += syscall.CmsgSpace(net.IPv4len)
}
if opt.isset(FlagInterface) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIP
m.Type = syscall.IP_RECVIF
m.Type = sysSockoptReceiveInterface
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrDatalink))
off += syscall.CmsgSpace(syscall.SizeofSockaddrDatalink)
}
@@ -89,33 +118,25 @@ func newControlMessage(opt *rawOpt) (oob []byte) {
return
}
func parseControlMessage(b []byte) (*ControlMessage, error) {
if len(b) == 0 {
return nil, nil
func (cm *ControlMessage) oobLen() (l int) {
if supportsPacketInfo && (cm.Src.To4() != nil || cm.IfIndex != 0) {
l += syscall.CmsgSpace(sysSizeofPacketInfo)
}
cmsgs, err := syscall.ParseSocketControlMessage(b)
if err != nil {
return nil, os.NewSyscallError("parse socket control message", err)
}
cm := &ControlMessage{}
for _, m := range cmsgs {
if m.Header.Level != ianaProtocolIP {
continue
}
switch m.Header.Type {
case syscall.IP_RECVTTL:
cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
case syscall.IP_RECVDSTADDR:
cm.Dst = m.Data[:net.IPv4len]
case syscall.IP_RECVIF:
sadl := (*syscall.SockaddrDatalink)(unsafe.Pointer(&m.Data[0]))
cm.IfIndex = int(sadl.Index)
}
}
return cm, nil
return
}
func marshalControlMessage(cm *ControlMessage) []byte {
// TODO(mikio): Implement IP_PKTINFO stuff when OS X 10.8 comes
return nil
func (cm *ControlMessage) parseControlMessage(m *syscall.SocketControlMessage) {
switch m.Header.Type {
case sysSockoptReceiveTTL:
cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
case sysSockoptReceiveDst:
cm.Dst = m.Data[:net.IPv4len]
case sysSockoptReceiveInterface:
sadl := (*syscall.SockaddrDatalink)(unsafe.Pointer(&m.Data[0]))
cm.IfIndex = int(sadl.Index)
case sysSockoptPacketInfo:
pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
cm.IfIndex = int(pi.IfIndex)
cm.Dst = pi.IP[:]
}
}

View File

@@ -5,15 +5,10 @@
package ipv4
import (
"os"
"syscall"
"unsafe"
)
// Linux provides a convenient path control option IP_PKTINFO that
// contains IP_SENDSRCADDR, IP_RECVDSTADDR, IP_RECVIF and IP_SENDIF.
const pktinfo = FlagSrc | FlagDst | FlagInterface
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
@@ -27,100 +22,63 @@ func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
opt.clear(FlagTTL)
}
}
if cf&pktinfo != 0 {
if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
if err := setIPv4PacketInfo(fd, on); err != nil {
return err
}
if on {
opt.set(cf & pktinfo)
opt.set(cf & (FlagSrc | FlagDst | FlagInterface))
} else {
opt.clear(cf & pktinfo)
opt.clear(cf & (FlagSrc | FlagDst | FlagInterface))
}
}
return nil
}
func newControlMessage(opt *rawOpt) (oob []byte) {
opt.Lock()
defer opt.Unlock()
l, off := 0, 0
func (opt *rawOpt) oobLen() (l int) {
if opt.isset(FlagTTL) {
l += syscall.CmsgSpace(1)
}
if opt.isset(pktinfo) {
l += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
}
if l > 0 {
oob = make([]byte, l)
if opt.isset(FlagTTL) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIP
m.Type = syscall.IP_RECVTTL
m.SetLen(syscall.CmsgLen(1))
off += syscall.CmsgSpace(1)
}
if opt.isset(pktinfo) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIP
m.Type = syscall.IP_PKTINFO
m.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
off += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
}
if opt.isset(FlagSrc | FlagDst | FlagInterface) {
l += syscall.CmsgSpace(sysSizeofPacketInfo)
}
return
}
func parseControlMessage(b []byte) (*ControlMessage, error) {
if len(b) == 0 {
return nil, nil
func (opt *rawOpt) marshalControlMessage() (oob []byte) {
var off int
oob = make([]byte, opt.oobLen())
if opt.isset(FlagTTL) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIP
m.Type = sysSockoptReceiveTTL
m.SetLen(syscall.CmsgLen(1))
off += syscall.CmsgSpace(1)
}
cmsgs, err := syscall.ParseSocketControlMessage(b)
if err != nil {
return nil, os.NewSyscallError("parse socket control message", err)
if opt.isset(FlagSrc | FlagDst | FlagInterface) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[0]))
m.Level = ianaProtocolIP
m.Type = sysSockoptPacketInfo
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
off += syscall.CmsgSpace(sysSizeofPacketInfo)
}
cm := &ControlMessage{}
for _, m := range cmsgs {
if m.Header.Level != ianaProtocolIP {
continue
}
switch m.Header.Type {
case syscall.IP_TTL:
cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
case syscall.IP_PKTINFO:
pi := (*syscall.Inet4Pktinfo)(unsafe.Pointer(&m.Data[0]))
cm.IfIndex = int(pi.Ifindex)
cm.Dst = pi.Addr[:]
}
}
return cm, nil
return
}
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
if cm == nil {
return
}
l, off := 0, 0
pion := false
func (cm *ControlMessage) oobLen() (l int) {
if cm.Src.To4() != nil || cm.IfIndex != 0 {
pion = true
l += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
}
if l > 0 {
oob = make([]byte, l)
if pion {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIP
m.Type = syscall.IP_PKTINFO
m.SetLen(syscall.CmsgLen(syscall.SizeofInet4Pktinfo))
pi := (*syscall.Inet4Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
if ip := cm.Src.To4(); ip != nil {
copy(pi.Addr[:], ip)
}
if cm.IfIndex != 0 {
pi.Ifindex = int32(cm.IfIndex)
}
off += syscall.CmsgSpace(syscall.SizeofInet4Pktinfo)
}
l += syscall.CmsgSpace(sysSizeofPacketInfo)
}
return
}
func (cm *ControlMessage) parseControlMessage(m *syscall.SocketControlMessage) {
switch m.Header.Type {
case sysSockoptTTL:
cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
case sysSockoptPacketInfo:
pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
cm.IfIndex = int(pi.IfIndex)
cm.Dst = pi.IP[:]
}
}

View File

@@ -0,0 +1,11 @@
// 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 !darwin,!linux
package ipv4
func (cm *ControlMessage) marshalPacketInfo() (oob []byte) {
return nil
}

30
ipv4/control_pktinfo.go Normal file
View File

@@ -0,0 +1,30 @@
// 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 darwin linux
package ipv4
import (
"syscall"
"unsafe"
)
func (cm *ControlMessage) marshalPacketInfo() (oob []byte) {
if l := cm.oobLen(); l > 0 {
oob = make([]byte, l)
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[0]))
m.Level = ianaProtocolIP
m.Type = sysSockoptPacketInfo
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
pi := (*sysPacketInfo)(unsafe.Pointer(&oob[syscall.CmsgLen(0)]))
if ip := cm.Src.To4(); ip != nil {
copy(pi.IP[:], ip)
}
if cm.IfIndex != 0 {
pi.IfIndex = int32(cm.IfIndex)
}
}
return
}

View File

@@ -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 dragonfly plan9 solaris
// +build plan9 solaris
package ipv4

43
ipv4/control_unix.go Normal file
View File

@@ -0,0 +1,43 @@
// Copyright 2012 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 ipv4
import (
"os"
"syscall"
)
func newControlMessage(opt *rawOpt) (oob []byte) {
opt.Lock()
defer opt.Unlock()
return opt.marshalControlMessage()
}
func parseControlMessage(b []byte) (*ControlMessage, error) {
if len(b) == 0 {
return nil, nil
}
cmsgs, err := syscall.ParseSocketControlMessage(b)
if err != nil {
return nil, os.NewSyscallError("parse socket control message", err)
}
cm := &ControlMessage{}
for _, m := range cmsgs {
if m.Header.Level != ianaProtocolIP {
continue
}
cm.parseControlMessage(&m)
}
return cm, nil
}
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
if cm == nil {
return nil
}
return cm.marshalPacketInfo()
}

View File

@@ -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 netbsd openbsd windows
// +build darwin dragonfly freebsd linux netbsd openbsd windows
package ipv4

View File

@@ -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 dragonfly plan9 solaris
// +build plan9 solaris
package ipv4

View File

@@ -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 netbsd openbsd windows
// +build darwin dragonfly freebsd linux netbsd openbsd windows
package ipv4

View File

@@ -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 dragonfly plan9 solaris
// +build plan9 solaris
package ipv4

View File

@@ -1,42 +0,0 @@
// Copyright 2012 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 freebsd linux netbsd openbsd windows
package ipv4
import (
"bytes"
"net"
"syscall"
)
func setSyscallIPMreq(mreq *syscall.IPMreq, ifi *net.Interface) error {
if ifi == nil {
return nil
}
ifat, err := ifi.Addrs()
if err != nil {
return err
}
for _, ifa := range ifat {
switch v := ifa.(type) {
case *net.IPAddr:
if a := v.IP.To4(); a != nil {
copy(mreq.Interface[:], a)
goto done
}
case *net.IPNet:
if a := v.IP.To4(); a != nil {
copy(mreq.Interface[:], a)
goto done
}
}
}
done:
if bytes.Equal(mreq.Multiaddr[:], net.IPv4zero.To4()) {
return errNoSuchMulticastInterface
}
return nil
}

View File

@@ -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 dragonfly plan9 solaris
// +build plan9 solaris
package ipv4

View File

@@ -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 netbsd openbsd
// +build darwin dragonfly freebsd linux netbsd openbsd
package ipv4

View File

@@ -56,8 +56,8 @@ func slicePacket(b []byte) (h, p []byte, err error) {
// WriteTo writes an IPv4 datagram through the endpoint c, copying the
// datagram from the IPv4 header h and the payload p. The control
// message cm allows the datagram path and the outgoing interface to be
// specified. Currently only Linux supports this. The cm may be nil
// if control of the outgoing datagram is not required.
// specified. Currently only Darwin and Linux support this. The cm
// may be nil if control of the outgoing datagram is not required.
//
// The IPv4 header h must contain appropriate fields that include:
//

View File

@@ -4,10 +4,7 @@
package ipv4
import (
"net"
"syscall"
)
import "net"
// A payloadHandler represents the IPv4 datagram payload handler.
type payloadHandler struct {
@@ -16,66 +13,3 @@ type payloadHandler struct {
}
func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil }
// ReadFrom reads a payload of the received IPv4 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, syscall.EINVAL
}
oob := newControlMessage(&c.rawOpt)
var oobn int
switch c := c.PacketConn.(type) {
case *net.UDPConn:
if n, oobn, _, src, err = c.ReadMsgUDP(b, oob); err != nil {
return 0, nil, nil, err
}
case *net.IPConn:
nb := make([]byte, maxHeaderLen+len(b))
if n, oobn, _, src, err = c.ReadMsgIP(nb, oob); err != nil {
return 0, nil, nil, err
}
hdrlen := int(nb[0]&0x0f) << 2
copy(b, nb[hdrlen:])
n -= hdrlen
default:
return 0, nil, nil, errInvalidConnType
}
if cm, err = parseControlMessage(oob[:oobn]); err != nil {
return 0, nil, nil, err
}
if cm != nil {
cm.Src = netAddrToIP4(src)
}
return
}
// WriteTo writes a payload of the IPv4 datagram, to the destination
// address dst through the endpoint c, copying the payload from b. It
// returns the number of bytes written. The control message cm allows
// the datagram path and the outgoing interface to be specified.
// Currently only Linux supports this. The cm may be nil if control
// of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, syscall.EINVAL
}
oob := marshalControlMessage(cm)
if dst == nil {
return 0, errMissingAddress
}
switch c := c.PacketConn.(type) {
case *net.UDPConn:
n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr))
case *net.IPConn:
n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr))
default:
return 0, errInvalidConnType
}
if err != nil {
return 0, err
}
return
}

75
ipv4/payload_cmsg.go Normal file
View File

@@ -0,0 +1,75 @@
// Copyright 2012 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 !plan9,!solaris,!windows
package ipv4
import (
"net"
"syscall"
)
// ReadFrom reads a payload of the received IPv4 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, syscall.EINVAL
}
oob := newControlMessage(&c.rawOpt)
var oobn int
switch c := c.PacketConn.(type) {
case *net.UDPConn:
if n, oobn, _, src, err = c.ReadMsgUDP(b, oob); err != nil {
return 0, nil, nil, err
}
case *net.IPConn:
nb := make([]byte, maxHeaderLen+len(b))
if n, oobn, _, src, err = c.ReadMsgIP(nb, oob); err != nil {
return 0, nil, nil, err
}
hdrlen := int(nb[0]&0x0f) << 2
copy(b, nb[hdrlen:])
n -= hdrlen
default:
return 0, nil, nil, errInvalidConnType
}
if cm, err = parseControlMessage(oob[:oobn]); err != nil {
return 0, nil, nil, err
}
if cm != nil {
cm.Src = netAddrToIP4(src)
}
return
}
// WriteTo writes a payload of the IPv4 datagram, to the destination
// address dst through the endpoint c, copying the payload from b. It
// returns the number of bytes written. The control message cm allows
// the datagram path and the outgoing interface to be specified.
// Currently only Darwin and Darwin support this. The cm may be nil if
// control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, syscall.EINVAL
}
oob := marshalControlMessage(cm)
if dst == nil {
return 0, errMissingAddress
}
switch c := c.PacketConn.(type) {
case *net.UDPConn:
n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr))
case *net.IPConn:
n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr))
default:
return 0, errInvalidConnType
}
if err != nil {
return 0, err
}
return
}

42
ipv4/payload_noncmsg.go Normal file
View File

@@ -0,0 +1,42 @@
// Copyright 2012 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 plan9 solaris windows
package ipv4
import (
"net"
"syscall"
)
// ReadFrom reads a payload of the received IPv4 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, syscall.EINVAL
}
if n, src, err = c.PacketConn.ReadFrom(b); err != nil {
return 0, nil, nil, err
}
return
}
// WriteTo writes a payload of the IPv4 datagram, to the destination
// address dst through the endpoint c, copying the payload from b. It
// returns the number of bytes written. The control message cm allows
// the datagram path and the outgoing interface to be specified.
// Currently only Darwin and Linux support this. The cm may be nil if
// control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, syscall.EINVAL
}
if dst == nil {
return 0, errMissingAddress
}
return c.PacketConn.WriteTo(b, dst)
}

View File

@@ -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 netbsd openbsd
// +build darwin dragonfly freebsd netbsd openbsd
package ipv4
@@ -13,7 +13,7 @@ import (
)
func ipv4MulticastTTL(fd int) (int, error) {
v, err := syscall.GetsockoptByte(fd, ianaProtocolIP, syscall.IP_MULTICAST_TTL)
v, err := syscall.GetsockoptByte(fd, ianaProtocolIP, sysSockoptMulticastTTL)
if err != nil {
return 0, os.NewSyscallError("getsockopt", err)
}
@@ -21,11 +21,11 @@ func ipv4MulticastTTL(fd int) (int, error) {
}
func setIPv4MulticastTTL(fd int, v int) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptByte(fd, ianaProtocolIP, syscall.IP_MULTICAST_TTL, byte(v)))
return os.NewSyscallError("setsockopt", syscall.SetsockoptByte(fd, ianaProtocolIP, sysSockoptMulticastTTL, byte(v)))
}
func ipv4ReceiveDestinationAddress(fd int) (bool, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_RECVDSTADDR)
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptReceiveDst)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
@@ -33,11 +33,11 @@ func ipv4ReceiveDestinationAddress(fd int) (bool, error) {
}
func setIPv4ReceiveDestinationAddress(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_RECVDSTADDR, boolint(v)))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptReceiveDst, boolint(v)))
}
func ipv4ReceiveInterface(fd int) (bool, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_RECVIF)
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptReceiveInterface)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
@@ -45,11 +45,11 @@ func ipv4ReceiveInterface(fd int) (bool, error) {
}
func setIPv4ReceiveInterface(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_RECVIF, boolint(v)))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptReceiveInterface, boolint(v)))
}
func ipv4MulticastInterface(fd int) (*net.Interface, error) {
v, err := syscall.GetsockoptInet4Addr(fd, ianaProtocolIP, syscall.IP_MULTICAST_IF)
v, err := syscall.GetsockoptInet4Addr(fd, ianaProtocolIP, sysSockoptMulticastInterface)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
@@ -63,11 +63,11 @@ func setIPv4MulticastInterface(fd int, ifi *net.Interface) error {
}
var v [4]byte
copy(v[:], ip.To4())
return os.NewSyscallError("setsockopt", syscall.SetsockoptInet4Addr(fd, ianaProtocolIP, syscall.IP_MULTICAST_IF, v))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInet4Addr(fd, ianaProtocolIP, sysSockoptMulticastInterface, v))
}
func ipv4MulticastLoopback(fd int) (bool, error) {
v, err := syscall.GetsockoptByte(fd, ianaProtocolIP, syscall.IP_MULTICAST_LOOP)
v, err := syscall.GetsockoptByte(fd, ianaProtocolIP, sysSockoptMulticastLoopback)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
@@ -75,21 +75,5 @@ func ipv4MulticastLoopback(fd int) (bool, error) {
}
func setIPv4MulticastLoopback(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptByte(fd, ianaProtocolIP, syscall.IP_MULTICAST_LOOP, byte(boolint(v))))
}
func joinIPv4Group(fd int, ifi *net.Interface, grp net.IP) error {
mreq := syscall.IPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if err := setSyscallIPMreq(&mreq, ifi); err != nil {
return err
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd, ianaProtocolIP, syscall.IP_ADD_MEMBERSHIP, &mreq))
}
func leaveIPv4Group(fd int, ifi *net.Interface, grp net.IP) error {
mreq := syscall.IPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if err := setSyscallIPMreq(&mreq, ifi); err != nil {
return err
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd, ianaProtocolIP, syscall.IP_DROP_MEMBERSHIP, &mreq))
return os.NewSyscallError("setsockopt", syscall.SetsockoptByte(fd, ianaProtocolIP, sysSockoptMulticastLoopback, byte(boolint(v))))
}

View File

@@ -11,7 +11,7 @@ import (
)
func ipv4ReceiveTOS(fd int) (bool, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_RECVTOS)
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptReceiveTOS)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
@@ -19,11 +19,11 @@ func ipv4ReceiveTOS(fd int) (bool, error) {
}
func setIPv4ReceiveTOS(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_RECVTOS, boolint(v)))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptReceiveTOS, boolint(v)))
}
func ipv4MulticastTTL(fd int) (int, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_MULTICAST_TTL)
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptMulticastTTL)
if err != nil {
return 0, os.NewSyscallError("getsockopt", err)
}
@@ -31,42 +31,30 @@ func ipv4MulticastTTL(fd int) (int, error) {
}
func setIPv4MulticastTTL(fd int, v int) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_MULTICAST_TTL, v))
}
func ipv4PacketInfo(fd int) (bool, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_PKTINFO)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4PacketInfo(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_PKTINFO, boolint(v)))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptMulticastTTL, v))
}
func ipv4MulticastInterface(fd int) (*net.Interface, error) {
mreqn, err := syscall.GetsockoptIPMreqn(fd, ianaProtocolIP, syscall.IP_MULTICAST_IF)
mreqn, err := syscall.GetsockoptIPMreqn(fd, ianaProtocolIP, sysSockoptMulticastInterface)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
if int(mreqn.Ifindex) == 0 {
if mreqn.Ifindex == 0 {
return nil, nil
}
return net.InterfaceByIndex(int(mreqn.Ifindex))
}
func setIPv4MulticastInterface(fd int, ifi *net.Interface) error {
mreqn := syscall.IPMreqn{}
var mreqn syscall.IPMreqn
if ifi != nil {
mreqn.Ifindex = int32(ifi.Index)
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreqn(fd, ianaProtocolIP, syscall.IP_MULTICAST_IF, &mreqn))
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreqn(fd, ianaProtocolIP, sysSockoptMulticastInterface, &mreqn))
}
func ipv4MulticastLoopback(fd int) (bool, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_MULTICAST_LOOP)
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptMulticastLoopback)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
@@ -74,21 +62,5 @@ func ipv4MulticastLoopback(fd int) (bool, error) {
}
func setIPv4MulticastLoopback(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_MULTICAST_LOOP, boolint(v)))
}
func joinIPv4Group(fd int, ifi *net.Interface, grp net.IP) error {
mreqn := syscall.IPMreqn{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if ifi != nil {
mreqn.Ifindex = int32(ifi.Index)
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreqn(fd, ianaProtocolIP, syscall.IP_ADD_MEMBERSHIP, &mreqn))
}
func leaveIPv4Group(fd int, ifi *net.Interface, grp net.IP) error {
mreqn := syscall.IPMreqn{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if ifi != nil {
mreqn.Ifindex = int32(ifi.Index)
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreqn(fd, ianaProtocolIP, syscall.IP_DROP_MEMBERSHIP, &mreqn))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptMulticastLoopback, boolint(v)))
}

29
ipv4/sockopt_mreq.go Normal file
View File

@@ -0,0 +1,29 @@
// Copyright 2012 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 netbsd openbsd
package ipv4
import (
"net"
"os"
"syscall"
)
func joinIPv4Group(fd int, ifi *net.Interface, grp net.IP) error {
mreq := syscall.IPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if err := setSysIPMreqInterface(&mreq, ifi); err != nil {
return err
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd, ianaProtocolIP, sysSockoptJoinGroup, &mreq))
}
func leaveIPv4Group(fd int, ifi *net.Interface, grp net.IP) error {
mreq := syscall.IPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if err := setSysIPMreqInterface(&mreq, ifi); err != nil {
return err
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd, ianaProtocolIP, sysSockoptLeaveGroup, &mreq))
}

29
ipv4/sockopt_mreqn.go Normal file
View File

@@ -0,0 +1,29 @@
// 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 freebsd linux
package ipv4
import (
"net"
"os"
"syscall"
)
func joinIPv4Group(fd int, ifi *net.Interface, grp net.IP) error {
mreqn := syscall.IPMreqn{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if ifi != nil {
mreqn.Ifindex = int32(ifi.Index)
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreqn(fd, ianaProtocolIP, sysSockoptJoinGroup, &mreqn))
}
func leaveIPv4Group(fd int, ifi *net.Interface, grp net.IP) error {
mreqn := syscall.IPMreqn{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if ifi != nil {
mreqn.Ifindex = int32(ifi.Index)
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreqn(fd, ianaProtocolIP, sysSockoptLeaveGroup, &mreqn))
}

View File

@@ -0,0 +1,15 @@
// 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 !darwin,!linux
package ipv4
func ipv4PacketInfo(fd int) (bool, error) {
return false, errOpNoSupport
}
func setIPv4PacketInfo(fd int, v bool) error {
return errOpNoSupport
}

View File

@@ -1,7 +1,9 @@
// Copyright 2012 The Go Authors. All rights reserved.
// 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 darwin linux
package ipv4
import (
@@ -9,14 +11,14 @@ import (
"syscall"
)
func ipv4SendSourceAddress(fd int) (bool, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_SENDSRCADDR)
func ipv4PacketInfo(fd int) (bool, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptPacketInfo)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
}
func setIPv4SendSourceAddress(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_SENDSRCADDR, boolint(v)))
func setIPv4PacketInfo(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptPacketInfo, boolint(v)))
}

View File

@@ -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 dragonfly plan9 solaris
// +build plan9 solaris
package ipv4

View File

@@ -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 netbsd openbsd
// +build darwin dragonfly freebsd linux netbsd openbsd
package ipv4
@@ -12,7 +12,7 @@ import (
)
func ipv4TOS(fd int) (int, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_TOS)
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptTOS)
if err != nil {
return 0, os.NewSyscallError("getsockopt", err)
}
@@ -20,11 +20,11 @@ func ipv4TOS(fd int) (int, error) {
}
func setIPv4TOS(fd int, v int) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_TOS, v))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptTOS, v))
}
func ipv4TTL(fd int) (int, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_TTL)
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptTTL)
if err != nil {
return 0, os.NewSyscallError("getsockopt", err)
}
@@ -32,11 +32,11 @@ func ipv4TTL(fd int) (int, error) {
}
func setIPv4TTL(fd int, v int) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_TTL, v))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptTTL, v))
}
func ipv4ReceiveTTL(fd int) (bool, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_RECVTTL)
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptReceiveTTL)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
@@ -44,11 +44,11 @@ func ipv4ReceiveTTL(fd int) (bool, error) {
}
func setIPv4ReceiveTTL(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_RECVTTL, boolint(v)))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptReceiveTTL, boolint(v)))
}
func ipv4HeaderPrepend(fd int) (bool, error) {
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_HDRINCL)
v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, sysSockoptHeaderPrepend)
if err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
@@ -56,5 +56,5 @@ func ipv4HeaderPrepend(fd int) (bool, error) {
}
func setIPv4HeaderPrepend(fd int, v bool) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, syscall.IP_HDRINCL, boolint(v)))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptHeaderPrepend, boolint(v)))
}

View File

@@ -17,7 +17,7 @@ import (
func ipv4TOS(fd syscall.Handle) (int, error) {
var v int32
l := int32(4)
if err := syscall.Getsockopt(fd, ianaProtocolIP, syscall.IP_TOS, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
if err := syscall.Getsockopt(fd, ianaProtocolIP, sysSockoptTOS, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
return 0, os.NewSyscallError("getsockopt", err)
}
return int(v), nil
@@ -25,13 +25,13 @@ func ipv4TOS(fd syscall.Handle) (int, error) {
func setIPv4TOS(fd syscall.Handle, v int) error {
vv := int32(v)
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, syscall.IP_TOS, (*byte)(unsafe.Pointer(&vv)), 4))
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, sysSockoptTOS, (*byte)(unsafe.Pointer(&vv)), 4))
}
func ipv4TTL(fd syscall.Handle) (int, error) {
var v int32
l := int32(4)
if err := syscall.Getsockopt(fd, ianaProtocolIP, syscall.IP_TTL, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
if err := syscall.Getsockopt(fd, ianaProtocolIP, sysSockoptTTL, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
return 0, os.NewSyscallError("getsockopt", err)
}
return int(v), nil
@@ -39,13 +39,13 @@ func ipv4TTL(fd syscall.Handle) (int, error) {
func setIPv4TTL(fd syscall.Handle, v int) error {
vv := int32(v)
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, syscall.IP_TTL, (*byte)(unsafe.Pointer(&vv)), 4))
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, sysSockoptTTL, (*byte)(unsafe.Pointer(&vv)), 4))
}
func ipv4MulticastTTL(fd syscall.Handle) (int, error) {
var v int32
l := int32(4)
if err := syscall.Getsockopt(fd, ianaProtocolIP, syscall.IP_MULTICAST_TTL, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
if err := syscall.Getsockopt(fd, ianaProtocolIP, sysSockoptMulticastTTL, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
return 0, os.NewSyscallError("getsockopt", err)
}
return int(v), nil
@@ -53,7 +53,7 @@ func ipv4MulticastTTL(fd syscall.Handle) (int, error) {
func setIPv4MulticastTTL(fd syscall.Handle, v int) error {
vv := int32(v)
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, syscall.IP_MULTICAST_TTL, (*byte)(unsafe.Pointer(&vv)), 4))
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, sysSockoptMulticastTTL, (*byte)(unsafe.Pointer(&vv)), 4))
}
func ipv4ReceiveTTL(fd syscall.Handle) (bool, error) {
@@ -99,7 +99,7 @@ func setIPv4ReceiveInterface(fd syscall.Handle, v bool) error {
func ipv4MulticastInterface(fd syscall.Handle) (*net.Interface, error) {
var v [4]byte
l := int32(4)
if err := syscall.Getsockopt(fd, ianaProtocolIP, syscall.IP_MULTICAST_IF, (*byte)(unsafe.Pointer(&v[0])), &l); err != nil {
if err := syscall.Getsockopt(fd, ianaProtocolIP, sysSockoptMulticastInterface, (*byte)(unsafe.Pointer(&v[0])), &l); err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
return netIP4ToInterface(net.IPv4(v[0], v[1], v[2], v[3]))
@@ -112,13 +112,13 @@ func setIPv4MulticastInterface(fd syscall.Handle, ifi *net.Interface) error {
}
var v [4]byte
copy(v[:], ip.To4())
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, syscall.IP_MULTICAST_IF, (*byte)(unsafe.Pointer(&v[0])), 4))
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, sysSockoptMulticastInterface, (*byte)(unsafe.Pointer(&v[0])), 4))
}
func ipv4MulticastLoopback(fd syscall.Handle) (bool, error) {
var v int32
l := int32(4)
if err := syscall.Getsockopt(fd, ianaProtocolIP, syscall.IP_MULTICAST_LOOP, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
if err := syscall.Getsockopt(fd, ianaProtocolIP, sysSockoptMulticastLoopback, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
return false, os.NewSyscallError("getsockopt", err)
}
return v == 1, nil
@@ -126,21 +126,21 @@ func ipv4MulticastLoopback(fd syscall.Handle) (bool, error) {
func setIPv4MulticastLoopback(fd syscall.Handle, v bool) error {
vv := int32(boolint(v))
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, syscall.IP_MULTICAST_LOOP, (*byte)(unsafe.Pointer(&vv)), 4))
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, sysSockoptMulticastLoopback, (*byte)(unsafe.Pointer(&vv)), 4))
}
func joinIPv4Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
mreq := syscall.IPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if err := setSyscallIPMreq(&mreq, ifi); err != nil {
if err := setSysIPMreqInterface(&mreq, ifi); err != nil {
return err
}
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, syscall.IP_ADD_MEMBERSHIP, (*byte)(unsafe.Pointer(&mreq)), int32(unsafe.Sizeof(mreq))))
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, sysSockoptJoinGroup, (*byte)(unsafe.Pointer(&mreq)), int32(unsafe.Sizeof(mreq))))
}
func leaveIPv4Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
mreq := syscall.IPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if err := setSyscallIPMreq(&mreq, ifi); err != nil {
if err := setSysIPMreqInterface(&mreq, ifi); err != nil {
return err
}
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, syscall.IP_DROP_MEMBERSHIP, (*byte)(unsafe.Pointer(&mreq)), int32(unsafe.Sizeof(mreq))))
return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIP, sysSockoptLeaveGroup, (*byte)(unsafe.Pointer(&mreq)), int32(unsafe.Sizeof(mreq))))
}

9
ipv4/sys.go Normal file
View File

@@ -0,0 +1,9 @@
// 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.
package ipv4
// supportsPacketInfo reports whether the platform supports
// IP_PKTINFO.
var supportsPacketInfo bool

37
ipv4/sys_bsd.go Normal file
View File

@@ -0,0 +1,37 @@
// 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 darwin dragonfly freebsd netbsd openbsd
package ipv4
import "syscall"
const (
// See /usr/include/netinet/in.h.
sysSockoptHeaderPrepend = syscall.IP_HDRINCL
sysSockoptTOS = syscall.IP_TOS
sysSockoptTTL = syscall.IP_TTL
sysSockoptMulticastTTL = syscall.IP_MULTICAST_TTL
sysSockoptMulticastInterface = syscall.IP_MULTICAST_IF
sysSockoptMulticastLoopback = syscall.IP_MULTICAST_LOOP
sysSockoptJoinGroup = syscall.IP_ADD_MEMBERSHIP
sysSockoptLeaveGroup = syscall.IP_DROP_MEMBERSHIP
)
const (
// See /usr/include/netinet/in.h.
sysSockoptReceiveTTL = syscall.IP_RECVTTL
sysSockoptReceiveDst = syscall.IP_RECVDSTADDR
sysSockoptReceiveInterface = syscall.IP_RECVIF
sysSockoptPacketInfo = 0x1a // only darwin supports this option for now
)
const sysSizeofPacketInfo = 0xc
type sysPacketInfo struct {
IfIndex int32
RoutedIP [4]byte
IP [4]byte
}

27
ipv4/sys_darwin.go Normal file
View File

@@ -0,0 +1,27 @@
// 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.
package ipv4
import "syscall"
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 IP_PKTINFO was 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' {
supportsPacketInfo = true
}
}

47
ipv4/sys_linux.go Normal file
View File

@@ -0,0 +1,47 @@
// 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.
package ipv4
import "syscall"
const (
// See /usr/include/linux/in.h.
sysSockoptHeaderPrepend = syscall.IP_HDRINCL
sysSockoptTOS = syscall.IP_TOS
sysSockoptTTL = syscall.IP_TTL
sysSockoptMulticastTTL = syscall.IP_MULTICAST_TTL
sysSockoptMulticastInterface = syscall.IP_MULTICAST_IF
sysSockoptMulticastLoopback = syscall.IP_MULTICAST_LOOP
sysSockoptJoinGroup = syscall.IP_ADD_MEMBERSHIP
sysSockoptLeaveGroup = syscall.IP_DROP_MEMBERSHIP
)
const (
// See /usr/include/linux/in.h.
sysSockoptReceiveTOS = syscall.IP_RECVTOS
sysSockoptReceiveTTL = syscall.IP_RECVTTL
sysSockoptPacketInfo = syscall.IP_PKTINFO
)
const (
sysSizeofNewMulticastReq = 0xc
sysSizeofPacketInfo = 0xc
)
type sysNewMulticastReq struct {
IP [4]byte
Interface [4]byte
IfIndex int32
}
type sysPacketInfo struct {
IfIndex int32
RoutedIP [4]byte
IP [4]byte
}
func init() {
supportsPacketInfo = true
}

37
ipv4/sys_mreq.go Normal file
View File

@@ -0,0 +1,37 @@
// 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 darwin dragonfly netbsd openbsd windows
package ipv4
import (
"net"
"syscall"
)
func setSysIPMreqInterface(mreq *syscall.IPMreq, ifi *net.Interface) error {
if ifi == nil {
return nil
}
ifat, err := ifi.Addrs()
if err != nil {
return err
}
for _, ifa := range ifat {
switch v := ifa.(type) {
case *net.IPAddr:
if ip := v.IP.To4(); ip != nil {
copy(mreq.Interface[:], ip)
return nil
}
case *net.IPNet:
if ip := v.IP.To4(); ip != nil {
copy(mreq.Interface[:], ip)
return nil
}
}
}
return errNoSuchInterface
}

31
ipv4/sys_windows.go Normal file
View File

@@ -0,0 +1,31 @@
// 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.
package ipv4
import "syscall"
const (
// See ws2tcpip.h.
sysSockoptHeaderPrepend = 0x2
sysSockoptTOS = syscall.IP_TOS
sysSockoptTTL = syscall.IP_TTL
sysSockoptMulticastTTL = syscall.IP_MULTICAST_TTL
sysSockoptMulticastInterface = syscall.IP_MULTICAST_IF
sysSockoptMulticastLoopback = syscall.IP_MULTICAST_LOOP
sysSockoptJoinGroup = syscall.IP_ADD_MEMBERSHIP
sysSockoptLeaveGroup = syscall.IP_DROP_MEMBERSHIP
)
const (
// See ws2tcpip.h.
sysSockoptPacketInfo = 0x13
)
const sysSizeofPacketInfo = 0x8
type sysPacketInfo struct {
IP [4]byte
IfIndex int32
}