control_rfc3542_linux.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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 (
  12. // See /usr/include/linux/in6.h.
  13. syscall_IPV6_RECVPATHMTU = syscall.IPV6_DSTOPTS + 1 + iota
  14. syscall_IPV6_PATHMTU
  15. syscall_IPV6_DONTFRAG
  16. )
  17. const pktinfo = FlagDst | FlagInterface
  18. func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
  19. opt.Lock()
  20. defer opt.Unlock()
  21. if cf&FlagTrafficClass != 0 {
  22. if err := setIPv6ReceiveTrafficClass(fd, on); err != nil {
  23. return err
  24. }
  25. if on {
  26. opt.set(FlagTrafficClass)
  27. } else {
  28. opt.clear(FlagTrafficClass)
  29. }
  30. }
  31. if cf&FlagHopLimit != 0 {
  32. if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
  33. return err
  34. }
  35. if on {
  36. opt.set(FlagHopLimit)
  37. } else {
  38. opt.clear(FlagHopLimit)
  39. }
  40. }
  41. if cf&pktinfo != 0 {
  42. if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
  43. return err
  44. }
  45. if on {
  46. opt.set(cf & pktinfo)
  47. } else {
  48. opt.clear(cf & pktinfo)
  49. }
  50. }
  51. if cf&FlagPathMTU != 0 {
  52. if err := setIPv6ReceivePathMTU(fd, on); err != nil {
  53. return err
  54. }
  55. if on {
  56. opt.set(FlagPathMTU)
  57. } else {
  58. opt.clear(FlagPathMTU)
  59. }
  60. }
  61. return nil
  62. }
  63. func newControlMessage(opt *rawOpt) (oob []byte) {
  64. opt.Lock()
  65. defer opt.Unlock()
  66. l, off := 0, 0
  67. if opt.isset(FlagTrafficClass) {
  68. l += syscall.CmsgSpace(4)
  69. }
  70. if opt.isset(FlagHopLimit) {
  71. l += syscall.CmsgSpace(4)
  72. }
  73. if opt.isset(pktinfo) {
  74. l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
  75. }
  76. if opt.isset(FlagPathMTU) {
  77. l += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
  78. }
  79. if l > 0 {
  80. oob = make([]byte, l)
  81. if opt.isset(FlagTrafficClass) {
  82. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  83. m.Level = ianaProtocolIPv6
  84. m.Type = syscall.IPV6_RECVTCLASS
  85. m.SetLen(syscall.CmsgLen(4))
  86. off += syscall.CmsgSpace(4)
  87. }
  88. if opt.isset(FlagHopLimit) {
  89. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  90. m.Level = ianaProtocolIPv6
  91. m.Type = syscall.IPV6_RECVHOPLIMIT
  92. m.SetLen(syscall.CmsgLen(4))
  93. off += syscall.CmsgSpace(4)
  94. }
  95. if opt.isset(pktinfo) {
  96. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  97. m.Level = ianaProtocolIPv6
  98. m.Type = syscall.IPV6_RECVPKTINFO
  99. m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
  100. off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
  101. }
  102. if opt.isset(FlagPathMTU) {
  103. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  104. m.Level = ianaProtocolIPv6
  105. m.Type = syscall_IPV6_RECVPATHMTU
  106. m.SetLen(syscall.CmsgLen(syscall.SizeofIPv6MTUInfo))
  107. off += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
  108. }
  109. }
  110. return
  111. }
  112. func parseControlMessage(b []byte) (*ControlMessage, error) {
  113. if len(b) == 0 {
  114. return nil, nil
  115. }
  116. cmsgs, err := syscall.ParseSocketControlMessage(b)
  117. if err != nil {
  118. return nil, os.NewSyscallError("parse socket control message", err)
  119. }
  120. cm := &ControlMessage{}
  121. for _, m := range cmsgs {
  122. if m.Header.Level != ianaProtocolIPv6 {
  123. continue
  124. }
  125. switch m.Header.Type {
  126. case syscall.IPV6_TCLASS:
  127. cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
  128. case syscall.IPV6_HOPLIMIT:
  129. cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
  130. case syscall.IPV6_PKTINFO:
  131. pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0]))
  132. cm.Dst = pi.Addr[:]
  133. cm.IfIndex = int(pi.Ifindex)
  134. case syscall_IPV6_PATHMTU:
  135. mi := (*syscall.IPv6MTUInfo)(unsafe.Pointer(&m.Data[0]))
  136. cm.Dst = mi.Addr.Addr[:]
  137. cm.IfIndex = int(mi.Addr.Scope_id)
  138. cm.MTU = int(mi.Mtu)
  139. }
  140. }
  141. return cm, nil
  142. }
  143. func marshalControlMessage(cm *ControlMessage) (oob []byte) {
  144. if cm == nil {
  145. return
  146. }
  147. l, off := 0, 0
  148. if cm.TrafficClass > 0 {
  149. l += syscall.CmsgSpace(4)
  150. }
  151. if cm.HopLimit > 0 {
  152. l += syscall.CmsgSpace(4)
  153. }
  154. pion := false
  155. if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
  156. pion = true
  157. l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
  158. }
  159. if len(cm.NextHop) == net.IPv6len {
  160. l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
  161. }
  162. if l > 0 {
  163. oob = make([]byte, l)
  164. if cm.TrafficClass > 0 {
  165. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  166. m.Level = ianaProtocolIPv6
  167. m.Type = syscall.IPV6_TCLASS
  168. m.SetLen(syscall.CmsgLen(4))
  169. data := oob[off+syscall.CmsgLen(0):]
  170. *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass)
  171. off += syscall.CmsgSpace(4)
  172. }
  173. if cm.HopLimit > 0 {
  174. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  175. m.Level = ianaProtocolIPv6
  176. m.Type = syscall.IPV6_HOPLIMIT
  177. m.SetLen(syscall.CmsgLen(4))
  178. data := oob[off+syscall.CmsgLen(0):]
  179. *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
  180. off += syscall.CmsgSpace(4)
  181. }
  182. if pion {
  183. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  184. m.Level = ianaProtocolIPv6
  185. m.Type = syscall.IPV6_PKTINFO
  186. m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
  187. pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
  188. if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
  189. copy(pi.Addr[:], ip)
  190. }
  191. if cm.IfIndex != 0 {
  192. pi.Ifindex = uint32(cm.IfIndex)
  193. }
  194. off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
  195. }
  196. if len(cm.NextHop) == net.IPv6len {
  197. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  198. m.Level = ianaProtocolIPv6
  199. m.Type = syscall.IPV6_NEXTHOP
  200. m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
  201. sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
  202. sa.Family = syscall.AF_INET6
  203. copy(sa.Addr[:], cm.NextHop)
  204. sa.Scope_id = uint32(cm.IfIndex)
  205. off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
  206. }
  207. }
  208. return
  209. }