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