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
diff --git a/ipv4/control_bsd.go b/ipv4/control_bsd.go
index 6b1b557..38ef01f 100644
--- a/ipv4/control_bsd.go
+++ b/ipv4/control_bsd.go
@@ -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 @@
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 @@
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[:]
+ }
}
diff --git a/ipv4/control_linux.go b/ipv4/control_linux.go
index fa7630f..5685367 100644
--- a/ipv4/control_linux.go
+++ b/ipv4/control_linux.go
@@ -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 @@
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[:]
+ }
+}
diff --git a/ipv4/control_nonpktinfo.go b/ipv4/control_nonpktinfo.go
new file mode 100644
index 0000000..c7da635
--- /dev/null
+++ b/ipv4/control_nonpktinfo.go
@@ -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
+}
diff --git a/ipv4/control_pktinfo.go b/ipv4/control_pktinfo.go
new file mode 100644
index 0000000..4778ef1
--- /dev/null
+++ b/ipv4/control_pktinfo.go
@@ -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
+}
diff --git a/ipv4/control_stub.go b/ipv4/control_stub.go
index 2b043a5..49b7f5c 100644
--- a/ipv4/control_stub.go
+++ b/ipv4/control_stub.go
@@ -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
diff --git a/ipv4/control_unix.go b/ipv4/control_unix.go
new file mode 100644
index 0000000..f3dd2f5
--- /dev/null
+++ b/ipv4/control_unix.go
@@ -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()
+}
diff --git a/ipv4/dgramopt_posix.go b/ipv4/dgramopt_posix.go
index 0ba81c2..874afde 100644
--- a/ipv4/dgramopt_posix.go
+++ b/ipv4/dgramopt_posix.go
@@ -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
diff --git a/ipv4/dgramopt_stub.go b/ipv4/dgramopt_stub.go
index b961a9a..794048f 100644
--- a/ipv4/dgramopt_stub.go
+++ b/ipv4/dgramopt_stub.go
@@ -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
diff --git a/ipv4/genericopt_posix.go b/ipv4/genericopt_posix.go
index f1eab2d..483c53a 100644
--- a/ipv4/genericopt_posix.go
+++ b/ipv4/genericopt_posix.go
@@ -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
diff --git a/ipv4/genericopt_stub.go b/ipv4/genericopt_stub.go
index b7bf373..342dfcf 100644
--- a/ipv4/genericopt_stub.go
+++ b/ipv4/genericopt_stub.go
@@ -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
diff --git a/ipv4/helper_posix.go b/ipv4/helper_posix.go
deleted file mode 100644
index 0adb3e1..0000000
--- a/ipv4/helper_posix.go
+++ /dev/null
@@ -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
-}
diff --git a/ipv4/helper_stub.go b/ipv4/helper_stub.go
index 3024860..03432d3 100644
--- a/ipv4/helper_stub.go
+++ b/ipv4/helper_stub.go
@@ -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
diff --git a/ipv4/helper_unix.go b/ipv4/helper_unix.go
index 3c12593..345ca7d 100644
--- a/ipv4/helper_unix.go
+++ b/ipv4/helper_unix.go
@@ -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
diff --git a/ipv4/packet.go b/ipv4/packet.go
index faeeec0..0986431 100644
--- a/ipv4/packet.go
+++ b/ipv4/packet.go
@@ -56,8 +56,8 @@
// 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:
//
diff --git a/ipv4/payload.go b/ipv4/payload.go
index 39efb4c..d7698cb 100644
--- a/ipv4/payload.go
+++ b/ipv4/payload.go
@@ -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 @@
}
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
-}
diff --git a/ipv4/payload_cmsg.go b/ipv4/payload_cmsg.go
new file mode 100644
index 0000000..2cda8b9
--- /dev/null
+++ b/ipv4/payload_cmsg.go
@@ -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
+}
diff --git a/ipv4/payload_noncmsg.go b/ipv4/payload_noncmsg.go
new file mode 100644
index 0000000..d128c9c
--- /dev/null
+++ b/ipv4/payload_noncmsg.go
@@ -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)
+}
diff --git a/ipv4/sockopt_bsd.go b/ipv4/sockopt_bsd.go
index 71e0bf0..b793f5c 100644
--- a/ipv4/sockopt_bsd.go
+++ b/ipv4/sockopt_bsd.go
@@ -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 @@
)
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 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 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 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 @@
}
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 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))))
}
diff --git a/ipv4/sockopt_freebsd.go b/ipv4/sockopt_freebsd.go
deleted file mode 100644
index 55c6de9..0000000
--- a/ipv4/sockopt_freebsd.go
+++ /dev/null
@@ -1,22 +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.
-
-package ipv4
-
-import (
- "os"
- "syscall"
-)
-
-func ipv4SendSourceAddress(fd int) (bool, error) {
- v, err := syscall.GetsockoptInt(fd, ianaProtocolIP, syscall.IP_SENDSRCADDR)
- 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)))
-}
diff --git a/ipv4/sockopt_linux.go b/ipv4/sockopt_linux.go
index cb5f6db..6ec58de 100644
--- a/ipv4/sockopt_linux.go
+++ b/ipv4/sockopt_linux.go
@@ -11,7 +11,7 @@
)
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 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 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 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)))
}
diff --git a/ipv4/sockopt_mreq.go b/ipv4/sockopt_mreq.go
new file mode 100644
index 0000000..6e591ca
--- /dev/null
+++ b/ipv4/sockopt_mreq.go
@@ -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))
+}
diff --git a/ipv4/sockopt_mreqn.go b/ipv4/sockopt_mreqn.go
new file mode 100644
index 0000000..a3a87d7
--- /dev/null
+++ b/ipv4/sockopt_mreqn.go
@@ -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))
+}
diff --git a/ipv4/sockopt_nonpktinfo.go b/ipv4/sockopt_nonpktinfo.go
new file mode 100644
index 0000000..5592b46
--- /dev/null
+++ b/ipv4/sockopt_nonpktinfo.go
@@ -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
+}
diff --git a/ipv4/sockopt_pktinfo.go b/ipv4/sockopt_pktinfo.go
new file mode 100644
index 0000000..5506b88
--- /dev/null
+++ b/ipv4/sockopt_pktinfo.go
@@ -0,0 +1,24 @@
+// 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 (
+ "os"
+ "syscall"
+)
+
+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 setIPv4PacketInfo(fd int, v bool) error {
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIP, sysSockoptPacketInfo, boolint(v)))
+}
diff --git a/ipv4/sockopt_stub.go b/ipv4/sockopt_stub.go
index fd9b9fd..53ae402 100644
--- a/ipv4/sockopt_stub.go
+++ b/ipv4/sockopt_stub.go
@@ -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
diff --git a/ipv4/sockopt_unix.go b/ipv4/sockopt_unix.go
index 3301656..a96fe25 100644
--- a/ipv4/sockopt_unix.go
+++ b/ipv4/sockopt_unix.go
@@ -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 @@
)
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 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 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 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 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)))
}
diff --git a/ipv4/sockopt_windows.go b/ipv4/sockopt_windows.go
index f7ee073..e6bf593 100644
--- a/ipv4/sockopt_windows.go
+++ b/ipv4/sockopt_windows.go
@@ -17,7 +17,7 @@
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 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 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 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 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 @@
}
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 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))))
}
diff --git a/ipv4/sys.go b/ipv4/sys.go
new file mode 100644
index 0000000..31cfbe2
--- /dev/null
+++ b/ipv4/sys.go
@@ -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
diff --git a/ipv4/sys_bsd.go b/ipv4/sys_bsd.go
new file mode 100644
index 0000000..866dadc
--- /dev/null
+++ b/ipv4/sys_bsd.go
@@ -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
+}
diff --git a/ipv4/sys_darwin.go b/ipv4/sys_darwin.go
new file mode 100644
index 0000000..3dee19d
--- /dev/null
+++ b/ipv4/sys_darwin.go
@@ -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
+ }
+}
diff --git a/ipv4/sys_linux.go b/ipv4/sys_linux.go
new file mode 100644
index 0000000..a81b592
--- /dev/null
+++ b/ipv4/sys_linux.go
@@ -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
+}
diff --git a/ipv4/sys_mreq.go b/ipv4/sys_mreq.go
new file mode 100644
index 0000000..6d5937c
--- /dev/null
+++ b/ipv4/sys_mreq.go
@@ -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
+}
diff --git a/ipv4/sys_windows.go b/ipv4/sys_windows.go
new file mode 100644
index 0000000..1ef7f2a
--- /dev/null
+++ b/ipv4/sys_windows.go
@@ -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
+}