control_bsd.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright 2012 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 dragonfly freebsd netbsd openbsd
  5. package ipv4
  6. import (
  7. "net"
  8. "syscall"
  9. "unsafe"
  10. )
  11. func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
  12. opt.Lock()
  13. defer opt.Unlock()
  14. if cf&FlagTTL != 0 {
  15. if err := setInt(fd, &sockOpts[ssoReceiveTTL], boolint(on)); err != nil {
  16. return err
  17. }
  18. if on {
  19. opt.set(FlagTTL)
  20. } else {
  21. opt.clear(FlagTTL)
  22. }
  23. }
  24. if sockOpts[ssoPacketInfo].name > 0 {
  25. if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
  26. if err := setInt(fd, &sockOpts[ssoPacketInfo], boolint(on)); err != nil {
  27. return err
  28. }
  29. if on {
  30. opt.set(cf & (FlagSrc | FlagDst | FlagInterface))
  31. } else {
  32. opt.clear(cf & (FlagSrc | FlagDst | FlagInterface))
  33. }
  34. }
  35. } else {
  36. if cf&FlagDst != 0 {
  37. if err := setInt(fd, &sockOpts[ssoReceiveDst], boolint(on)); err != nil {
  38. return err
  39. }
  40. if on {
  41. opt.set(FlagDst)
  42. } else {
  43. opt.clear(FlagDst)
  44. }
  45. }
  46. if cf&FlagInterface != 0 {
  47. if err := setInt(fd, &sockOpts[ssoReceiveInterface], boolint(on)); err != nil {
  48. return err
  49. }
  50. if on {
  51. opt.set(FlagInterface)
  52. } else {
  53. opt.clear(FlagInterface)
  54. }
  55. }
  56. }
  57. return nil
  58. }
  59. func (opt *rawOpt) oobLen() (l int) {
  60. if opt.isset(FlagTTL) {
  61. l += syscall.CmsgSpace(1)
  62. }
  63. if sockOpts[ssoPacketInfo].name > 0 {
  64. if opt.isset(FlagSrc | FlagDst | FlagInterface) {
  65. l += syscall.CmsgSpace(sysSizeofInetPktinfo)
  66. }
  67. } else {
  68. if opt.isset(FlagDst) {
  69. l += syscall.CmsgSpace(net.IPv4len)
  70. }
  71. if opt.isset(FlagInterface) {
  72. l += syscall.CmsgSpace(syscall.SizeofSockaddrDatalink)
  73. }
  74. }
  75. return
  76. }
  77. func (opt *rawOpt) marshalControlMessage() (oob []byte) {
  78. var off int
  79. oob = make([]byte, opt.oobLen())
  80. if opt.isset(FlagTTL) {
  81. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  82. m.Level = ianaProtocolIP
  83. m.Type = sysIP_RECVTTL
  84. m.SetLen(syscall.CmsgLen(1))
  85. off += syscall.CmsgSpace(1)
  86. }
  87. if sockOpts[ssoPacketInfo].name > 0 {
  88. if opt.isset(FlagSrc | FlagDst | FlagInterface) {
  89. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  90. m.Level = ianaProtocolIP
  91. m.Type = sysIP_PKTINFO
  92. m.SetLen(syscall.CmsgLen(sysSizeofInetPktinfo))
  93. off += syscall.CmsgSpace(sysSizeofInetPktinfo)
  94. }
  95. } else {
  96. if opt.isset(FlagDst) {
  97. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  98. m.Level = ianaProtocolIP
  99. m.Type = sysIP_RECVDSTADDR
  100. m.SetLen(syscall.CmsgLen(net.IPv4len))
  101. off += syscall.CmsgSpace(net.IPv4len)
  102. }
  103. if opt.isset(FlagInterface) {
  104. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  105. m.Level = ianaProtocolIP
  106. m.Type = sysIP_RECVIF
  107. m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrDatalink))
  108. off += syscall.CmsgSpace(syscall.SizeofSockaddrDatalink)
  109. }
  110. }
  111. return
  112. }
  113. func (cm *ControlMessage) oobLen() (l int) {
  114. if sockOpts[ssoPacketInfo].name > 0 && (cm.Src.To4() != nil || cm.IfIndex != 0) {
  115. l += syscall.CmsgSpace(sysSizeofInetPktinfo)
  116. }
  117. return
  118. }
  119. func (cm *ControlMessage) parseControlMessage(m *syscall.SocketControlMessage) {
  120. switch m.Header.Type {
  121. case sysIP_RECVTTL:
  122. cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
  123. case sysIP_RECVDSTADDR:
  124. cm.Dst = m.Data[:net.IPv4len]
  125. case sysIP_RECVIF:
  126. sadl := (*syscall.SockaddrDatalink)(unsafe.Pointer(&m.Data[0]))
  127. cm.IfIndex = int(sadl.Index)
  128. case sysIP_PKTINFO:
  129. pi := (*sysInetPktinfo)(unsafe.Pointer(&m.Data[0]))
  130. cm.IfIndex = int(pi.Ifindex)
  131. cm.Dst = pi.Addr[:]
  132. }
  133. }