control_bsd.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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 freebsd netbsd openbsd
  5. package ipv4
  6. import (
  7. "net"
  8. "os"
  9. "syscall"
  10. "unsafe"
  11. )
  12. func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
  13. opt.Lock()
  14. defer opt.Unlock()
  15. if cf&FlagTTL != 0 {
  16. if err := setIPv4ReceiveTTL(fd, on); err != nil {
  17. return err
  18. }
  19. if on {
  20. opt.set(FlagTTL)
  21. } else {
  22. opt.clear(FlagTTL)
  23. }
  24. }
  25. if cf&FlagDst != 0 {
  26. if err := setIPv4ReceiveDestinationAddress(fd, on); err != nil {
  27. return err
  28. }
  29. if on {
  30. opt.set(FlagDst)
  31. } else {
  32. opt.clear(FlagDst)
  33. }
  34. }
  35. if cf&FlagInterface != 0 {
  36. if err := setIPv4ReceiveInterface(fd, on); err != nil {
  37. return err
  38. }
  39. if on {
  40. opt.set(FlagInterface)
  41. } else {
  42. opt.clear(FlagInterface)
  43. }
  44. }
  45. return nil
  46. }
  47. func newControlMessage(opt *rawOpt) (oob []byte) {
  48. opt.Lock()
  49. defer opt.Unlock()
  50. l, off := 0, 0
  51. if opt.isset(FlagTTL) {
  52. l += syscall.CmsgSpace(1)
  53. }
  54. if opt.isset(FlagDst) {
  55. l += syscall.CmsgSpace(net.IPv4len)
  56. }
  57. if opt.isset(FlagInterface) {
  58. l += syscall.CmsgSpace(syscall.SizeofSockaddrDatalink)
  59. }
  60. if l > 0 {
  61. oob = make([]byte, l)
  62. if opt.isset(FlagTTL) {
  63. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  64. m.Level = ianaProtocolIP
  65. m.Type = syscall.IP_RECVTTL
  66. m.SetLen(syscall.CmsgLen(1))
  67. off += syscall.CmsgSpace(1)
  68. }
  69. if opt.isset(FlagDst) {
  70. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  71. m.Level = ianaProtocolIP
  72. m.Type = syscall.IP_RECVDSTADDR
  73. m.SetLen(syscall.CmsgLen(net.IPv4len))
  74. off += syscall.CmsgSpace(net.IPv4len)
  75. }
  76. if opt.isset(FlagInterface) {
  77. m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
  78. m.Level = ianaProtocolIP
  79. m.Type = syscall.IP_RECVIF
  80. m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrDatalink))
  81. off += syscall.CmsgSpace(syscall.SizeofSockaddrDatalink)
  82. }
  83. }
  84. return
  85. }
  86. func parseControlMessage(b []byte) (*ControlMessage, error) {
  87. if len(b) == 0 {
  88. return nil, nil
  89. }
  90. cmsgs, err := syscall.ParseSocketControlMessage(b)
  91. if err != nil {
  92. return nil, os.NewSyscallError("parse socket control message", err)
  93. }
  94. cm := &ControlMessage{}
  95. for _, m := range cmsgs {
  96. if m.Header.Level != ianaProtocolIP {
  97. continue
  98. }
  99. switch m.Header.Type {
  100. case syscall.IP_RECVTTL:
  101. cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
  102. case syscall.IP_RECVDSTADDR:
  103. cm.Dst = m.Data[:net.IPv4len]
  104. case syscall.IP_RECVIF:
  105. sadl := (*syscall.SockaddrDatalink)(unsafe.Pointer(&m.Data[0]))
  106. cm.IfIndex = int(sadl.Index)
  107. }
  108. }
  109. return cm, nil
  110. }
  111. func marshalControlMessage(cm *ControlMessage) []byte {
  112. // TODO(mikio): Implement IP_PKTINFO stuff when OS X 10.8 comes
  113. return nil
  114. }