|
@@ -2,209 +2,96 @@
|
|
|
// Use of this source code is governed by a BSD-style
|
|
// Use of this source code is governed by a BSD-style
|
|
|
// license that can be found in the LICENSE file.
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
-// +build dragonfly freebsd linux netbsd openbsd
|
|
|
|
|
|
|
+// +build darwin dragonfly freebsd linux netbsd openbsd
|
|
|
|
|
|
|
|
package ipv6
|
|
package ipv6
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
- "net"
|
|
|
|
|
- "os"
|
|
|
|
|
"syscall"
|
|
"syscall"
|
|
|
"unsafe"
|
|
"unsafe"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
-const pktinfo = FlagDst | FlagInterface
|
|
|
|
|
|
|
+func marshalTrafficClass(b []byte, cm *ControlMessage) []byte {
|
|
|
|
|
+ m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
|
|
|
|
|
+ m.Level = ianaProtocolIPv6
|
|
|
|
|
+ m.Type = sysIPV6_TCLASS
|
|
|
|
|
+ m.SetLen(syscall.CmsgLen(4))
|
|
|
|
|
+ if cm != nil {
|
|
|
|
|
+ data := b[syscall.CmsgLen(0):]
|
|
|
|
|
+ *(*int32)(unsafe.Pointer(&data[:4][0])) = int32(cm.TrafficClass)
|
|
|
|
|
+ }
|
|
|
|
|
+ return b[syscall.CmsgSpace(4):]
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
|
|
|
|
|
- opt.Lock()
|
|
|
|
|
- defer opt.Unlock()
|
|
|
|
|
- if cf&FlagTrafficClass != 0 {
|
|
|
|
|
- if err := setIPv6ReceiveTrafficClass(fd, on); err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- if on {
|
|
|
|
|
- opt.set(FlagTrafficClass)
|
|
|
|
|
- } else {
|
|
|
|
|
- opt.clear(FlagTrafficClass)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if cf&FlagHopLimit != 0 {
|
|
|
|
|
- if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- if on {
|
|
|
|
|
- opt.set(FlagHopLimit)
|
|
|
|
|
- } else {
|
|
|
|
|
- opt.clear(FlagHopLimit)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if cf&pktinfo != 0 {
|
|
|
|
|
- if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- if on {
|
|
|
|
|
- opt.set(cf & pktinfo)
|
|
|
|
|
- } else {
|
|
|
|
|
- opt.clear(cf & pktinfo)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if cf&FlagPathMTU != 0 {
|
|
|
|
|
- if err := setIPv6ReceivePathMTU(fd, on); err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- if on {
|
|
|
|
|
- opt.set(FlagPathMTU)
|
|
|
|
|
- } else {
|
|
|
|
|
- opt.clear(FlagPathMTU)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return nil
|
|
|
|
|
|
|
+func parseTrafficClass(cm *ControlMessage, b []byte) {
|
|
|
|
|
+ cm.TrafficClass = int(*(*int32)(unsafe.Pointer(&b[:4][0])))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func newControlMessage(opt *rawOpt) (oob []byte) {
|
|
|
|
|
- opt.Lock()
|
|
|
|
|
- defer opt.Unlock()
|
|
|
|
|
- l, off := 0, 0
|
|
|
|
|
- if opt.isset(FlagTrafficClass) {
|
|
|
|
|
- l += syscall.CmsgSpace(4)
|
|
|
|
|
- }
|
|
|
|
|
- if opt.isset(FlagHopLimit) {
|
|
|
|
|
- l += syscall.CmsgSpace(4)
|
|
|
|
|
- }
|
|
|
|
|
- if opt.isset(pktinfo) {
|
|
|
|
|
- l += syscall.CmsgSpace(sysSizeofPacketInfo)
|
|
|
|
|
- }
|
|
|
|
|
- if opt.isset(FlagPathMTU) {
|
|
|
|
|
- l += syscall.CmsgSpace(sysSizeofMTUInfo)
|
|
|
|
|
- }
|
|
|
|
|
- if l > 0 {
|
|
|
|
|
- oob = make([]byte, l)
|
|
|
|
|
- if opt.isset(FlagTrafficClass) {
|
|
|
|
|
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
|
|
|
- m.Level = ianaProtocolIPv6
|
|
|
|
|
- m.Type = sysSockoptReceiveTrafficClass
|
|
|
|
|
- m.SetLen(syscall.CmsgLen(4))
|
|
|
|
|
- off += syscall.CmsgSpace(4)
|
|
|
|
|
- }
|
|
|
|
|
- if opt.isset(FlagHopLimit) {
|
|
|
|
|
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
|
|
|
- m.Level = ianaProtocolIPv6
|
|
|
|
|
- m.Type = sysSockoptReceiveHopLimit
|
|
|
|
|
- m.SetLen(syscall.CmsgLen(4))
|
|
|
|
|
- off += syscall.CmsgSpace(4)
|
|
|
|
|
- }
|
|
|
|
|
- if opt.isset(pktinfo) {
|
|
|
|
|
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
|
|
|
- m.Level = ianaProtocolIPv6
|
|
|
|
|
- m.Type = sysSockoptReceivePacketInfo
|
|
|
|
|
- m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
|
|
|
|
|
- off += syscall.CmsgSpace(sysSizeofPacketInfo)
|
|
|
|
|
- }
|
|
|
|
|
- if opt.isset(FlagPathMTU) {
|
|
|
|
|
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
|
|
|
- m.Level = ianaProtocolIPv6
|
|
|
|
|
- m.Type = sysSockoptReceivePathMTU
|
|
|
|
|
- m.SetLen(syscall.CmsgLen(sysSizeofMTUInfo))
|
|
|
|
|
- off += syscall.CmsgSpace(sysSizeofMTUInfo)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return
|
|
|
|
|
|
|
+func marshalHopLimit(b []byte, cm *ControlMessage) []byte {
|
|
|
|
|
+ m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
|
|
|
|
|
+ m.Level = ianaProtocolIPv6
|
|
|
|
|
+ m.Type = sysIPV6_HOPLIMIT
|
|
|
|
|
+ m.SetLen(syscall.CmsgLen(4))
|
|
|
|
|
+ if cm != nil {
|
|
|
|
|
+ data := b[syscall.CmsgLen(0):]
|
|
|
|
|
+ *(*int32)(unsafe.Pointer(&data[:4][0])) = int32(cm.HopLimit)
|
|
|
|
|
+ }
|
|
|
|
|
+ return b[syscall.CmsgSpace(4):]
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-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 != ianaProtocolIPv6 {
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
- switch m.Header.Type {
|
|
|
|
|
- case sysSockoptTrafficClass:
|
|
|
|
|
- cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
|
|
|
|
- case sysSockoptHopLimit:
|
|
|
|
|
- cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
|
|
|
|
|
- case sysSockoptPacketInfo:
|
|
|
|
|
- pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
|
|
|
|
|
- cm.Dst = pi.IP[:]
|
|
|
|
|
- cm.IfIndex = int(pi.IfIndex)
|
|
|
|
|
- case sysSockoptPathMTU:
|
|
|
|
|
- mi := (*sysMTUInfo)(unsafe.Pointer(&m.Data[0]))
|
|
|
|
|
- cm.Dst = mi.Addr.Addr[:]
|
|
|
|
|
- cm.IfIndex = int(mi.Addr.Scope_id)
|
|
|
|
|
- cm.MTU = int(mi.MTU)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return cm, nil
|
|
|
|
|
|
|
+func parseHopLimit(cm *ControlMessage, b []byte) {
|
|
|
|
|
+ cm.HopLimit = int(*(*int32)(unsafe.Pointer(&b[:4][0])))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func marshalControlMessage(cm *ControlMessage) (oob []byte) {
|
|
|
|
|
- if cm == nil {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- l, off := 0, 0
|
|
|
|
|
- if cm.TrafficClass > 0 {
|
|
|
|
|
- l += syscall.CmsgSpace(4)
|
|
|
|
|
- }
|
|
|
|
|
- if cm.HopLimit > 0 {
|
|
|
|
|
- l += syscall.CmsgSpace(4)
|
|
|
|
|
- }
|
|
|
|
|
- pion := false
|
|
|
|
|
- if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
|
|
|
|
|
- pion = true
|
|
|
|
|
- l += syscall.CmsgSpace(sysSizeofPacketInfo)
|
|
|
|
|
- }
|
|
|
|
|
- if len(cm.NextHop) == net.IPv6len {
|
|
|
|
|
- l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
|
|
|
|
- }
|
|
|
|
|
- if l > 0 {
|
|
|
|
|
- oob = make([]byte, l)
|
|
|
|
|
- if cm.TrafficClass > 0 {
|
|
|
|
|
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
|
|
|
- m.Level = ianaProtocolIPv6
|
|
|
|
|
- m.Type = sysSockoptTrafficClass
|
|
|
|
|
- m.SetLen(syscall.CmsgLen(4))
|
|
|
|
|
- data := oob[off+syscall.CmsgLen(0):]
|
|
|
|
|
- *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass)
|
|
|
|
|
- off += syscall.CmsgSpace(4)
|
|
|
|
|
- }
|
|
|
|
|
- if cm.HopLimit > 0 {
|
|
|
|
|
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
|
|
|
- m.Level = ianaProtocolIPv6
|
|
|
|
|
- m.Type = sysSockoptHopLimit
|
|
|
|
|
- m.SetLen(syscall.CmsgLen(4))
|
|
|
|
|
- data := oob[off+syscall.CmsgLen(0):]
|
|
|
|
|
- *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
|
|
|
|
|
- off += syscall.CmsgSpace(4)
|
|
|
|
|
|
|
+func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
|
|
|
|
|
+ m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
|
|
|
|
|
+ m.Level = ianaProtocolIPv6
|
|
|
|
|
+ m.Type = sysIPV6_PKTINFO
|
|
|
|
|
+ m.SetLen(syscall.CmsgLen(sysSizeofInet6Pktinfo))
|
|
|
|
|
+ if cm != nil {
|
|
|
|
|
+ pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
|
|
|
|
|
+ if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
|
|
|
|
|
+ copy(pi.Addr[:], ip)
|
|
|
}
|
|
}
|
|
|
- if pion {
|
|
|
|
|
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
|
|
|
- m.Level = ianaProtocolIPv6
|
|
|
|
|
- m.Type = sysSockoptPacketInfo
|
|
|
|
|
- m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
|
|
|
|
|
- pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
|
|
|
|
- if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
|
|
|
|
|
- copy(pi.IP[:], ip)
|
|
|
|
|
- }
|
|
|
|
|
- if cm.IfIndex != 0 {
|
|
|
|
|
- pi.IfIndex = uint32(cm.IfIndex)
|
|
|
|
|
- }
|
|
|
|
|
- off += syscall.CmsgSpace(sysSizeofPacketInfo)
|
|
|
|
|
- }
|
|
|
|
|
- if len(cm.NextHop) == net.IPv6len {
|
|
|
|
|
- m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
|
|
|
|
|
- m.Level = ianaProtocolIPv6
|
|
|
|
|
- m.Type = sysSockoptNextHop
|
|
|
|
|
- m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
|
|
|
|
|
- sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
|
|
|
|
|
- setSockaddr(sa, cm.NextHop, cm.IfIndex)
|
|
|
|
|
- off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
|
|
|
|
|
|
|
+ if cm.IfIndex > 0 {
|
|
|
|
|
+ pi.setIfindex(cm.IfIndex)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- return
|
|
|
|
|
|
|
+ return b[syscall.CmsgSpace(sysSizeofInet6Pktinfo):]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func parsePacketInfo(cm *ControlMessage, b []byte) {
|
|
|
|
|
+ pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[0]))
|
|
|
|
|
+ cm.Dst = pi.Addr[:]
|
|
|
|
|
+ cm.IfIndex = int(pi.Ifindex)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func marshalNextHop(b []byte, cm *ControlMessage) []byte {
|
|
|
|
|
+ m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
|
|
|
|
|
+ m.Level = ianaProtocolIPv6
|
|
|
|
|
+ m.Type = sysIPV6_NEXTHOP
|
|
|
|
|
+ m.SetLen(syscall.CmsgLen(sysSizeofSockaddrInet6))
|
|
|
|
|
+ if cm != nil {
|
|
|
|
|
+ sa := (*sysSockaddrInet6)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
|
|
|
|
|
+ sa.setSockaddr(cm.NextHop, cm.IfIndex)
|
|
|
|
|
+ }
|
|
|
|
|
+ return b[syscall.CmsgSpace(sysSizeofSockaddrInet6):]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func parseNextHop(cm *ControlMessage, b []byte) {
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func marshalPathMTU(b []byte, cm *ControlMessage) []byte {
|
|
|
|
|
+ m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
|
|
|
|
|
+ m.Level = ianaProtocolIPv6
|
|
|
|
|
+ m.Type = sysIPV6_PATHMTU
|
|
|
|
|
+ m.SetLen(syscall.CmsgLen(sysSizeofIPv6Mtuinfo))
|
|
|
|
|
+ return b[syscall.CmsgSpace(sysSizeofIPv6Mtuinfo):]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func parsePathMTU(cm *ControlMessage, b []byte) {
|
|
|
|
|
+ mi := (*sysIPv6Mtuinfo)(unsafe.Pointer(&b[0]))
|
|
|
|
|
+ cm.Dst = mi.Addr.Addr[:]
|
|
|
|
|
+ cm.IfIndex = int(mi.Addr.Scope_id)
|
|
|
|
|
+ cm.MTU = int(mi.Mtu)
|
|
|
}
|
|
}
|