control_rfc2292_unix.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build darwin
  5. package ipv6
  6. import (
  7. "net"
  8. "os"
  9. "syscall"
  10. "unsafe"
  11. )
  12. const pktinfo = FlagDst | FlagInterface
  13. func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
  14. opt.Lock()
  15. defer opt.Unlock()
  16. if cf&FlagHopLimit != 0 {
  17. if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
  18. return err
  19. }
  20. if on {
  21. opt.set(FlagHopLimit)
  22. } else {
  23. opt.clear(FlagHopLimit)
  24. }
  25. }
  26. if cf&pktinfo != 0 {
  27. if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
  28. return err
  29. }
  30. if on {
  31. opt.set(cf & pktinfo)
  32. } else {
  33. opt.clear(cf & pktinfo)
  34. }
  35. }
  36. return nil
  37. }
  38. func newControlMessage(opt *rawOpt) (oob []byte) {
  39. opt.Lock()
  40. defer opt.Unlock()
  41. l, off := 0, 0
  42. if opt.isset(FlagHopLimit) {
  43. l += syscall.CmsgSpace(4)
  44. }
  45. if opt.isset(pktinfo) {
  46. l += syscall.CmsgSpace(sysSizeofPacketInfo)
  47. }
  48. if l > 0 {
  49. oob = make([]byte, l)
  50. if opt.isset(FlagHopLimit) {
  51. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  52. m.Level = ianaProtocolIPv6
  53. m.Type = sysSockopt2292HopLimit
  54. m.SetLen(syscall.CmsgLen(4))
  55. off += syscall.CmsgSpace(4)
  56. }
  57. if opt.isset(pktinfo) {
  58. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  59. m.Level = ianaProtocolIPv6
  60. m.Type = sysSockopt2292PacketInfo
  61. m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
  62. off += syscall.CmsgSpace(sysSizeofPacketInfo)
  63. }
  64. }
  65. return
  66. }
  67. func parseControlMessage(b []byte) (*ControlMessage, error) {
  68. if len(b) == 0 {
  69. return nil, nil
  70. }
  71. cmsgs, err := syscall.ParseSocketControlMessage(b)
  72. if err != nil {
  73. return nil, os.NewSyscallError("parse socket control message", err)
  74. }
  75. cm := &ControlMessage{}
  76. for _, m := range cmsgs {
  77. if m.Header.Level != ianaProtocolIPv6 {
  78. continue
  79. }
  80. switch m.Header.Type {
  81. case sysSockopt2292HopLimit:
  82. cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
  83. case sysSockopt2292PacketInfo:
  84. pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
  85. cm.IfIndex = int(pi.IfIndex)
  86. cm.Dst = pi.IP[:]
  87. }
  88. }
  89. return cm, nil
  90. }
  91. func marshalControlMessage(cm *ControlMessage) (oob []byte) {
  92. if cm == nil {
  93. return
  94. }
  95. l, off := 0, 0
  96. if cm.HopLimit > 0 {
  97. l += syscall.CmsgSpace(4)
  98. }
  99. pion := false
  100. if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
  101. pion = true
  102. l += syscall.CmsgSpace(sysSizeofPacketInfo)
  103. }
  104. if len(cm.NextHop) == net.IPv6len {
  105. l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
  106. }
  107. if l > 0 {
  108. oob = make([]byte, l)
  109. if cm.HopLimit > 0 {
  110. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  111. m.Level = ianaProtocolIPv6
  112. m.Type = sysSockopt2292HopLimit
  113. m.SetLen(syscall.CmsgLen(4))
  114. data := oob[off+syscall.CmsgLen(0):]
  115. *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
  116. off += syscall.CmsgSpace(4)
  117. }
  118. if pion {
  119. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  120. m.Level = ianaProtocolIPv6
  121. m.Type = sysSockopt2292PacketInfo
  122. m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
  123. pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
  124. if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
  125. copy(pi.IP[:], ip)
  126. }
  127. if cm.IfIndex != 0 {
  128. pi.IfIndex = uint32(cm.IfIndex)
  129. }
  130. off += syscall.CmsgSpace(sysSizeofPacketInfo)
  131. }
  132. if len(cm.NextHop) == net.IPv6len {
  133. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  134. m.Level = ianaProtocolIPv6
  135. m.Type = sysSockopt2292NextHop
  136. m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
  137. sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
  138. setSockaddr(sa, cm.NextHop, cm.IfIndex)
  139. off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
  140. }
  141. }
  142. return
  143. }