control_bsd.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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. if opt.isset(FlagTTL) {
  51. b := make([]byte, syscall.CmsgSpace(1))
  52. cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
  53. cmsg.Level = syscall.IPPROTO_IP
  54. cmsg.Type = syscall.IP_RECVTTL
  55. cmsg.SetLen(syscall.CmsgLen(1))
  56. oob = append(oob, b...)
  57. }
  58. if opt.isset(FlagDst) {
  59. b := make([]byte, syscall.CmsgSpace(net.IPv4len))
  60. cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
  61. cmsg.Level = syscall.IPPROTO_IP
  62. cmsg.Type = syscall.IP_RECVDSTADDR
  63. cmsg.SetLen(syscall.CmsgLen(net.IPv4len))
  64. oob = append(oob, b...)
  65. }
  66. if opt.isset(FlagInterface) {
  67. b := make([]byte, syscall.CmsgSpace(syscall.SizeofSockaddrDatalink))
  68. cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
  69. cmsg.Level = syscall.IPPROTO_IP
  70. cmsg.Type = syscall.IP_RECVIF
  71. cmsg.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrDatalink))
  72. oob = append(oob, b...)
  73. }
  74. return
  75. }
  76. func parseControlMessage(b []byte) (*ControlMessage, error) {
  77. cmsgs, err := syscall.ParseSocketControlMessage(b)
  78. if err != nil {
  79. return nil, os.NewSyscallError("parse socket control message", err)
  80. }
  81. if len(b) == 0 {
  82. return nil, nil
  83. }
  84. cm := &ControlMessage{}
  85. for _, m := range cmsgs {
  86. if m.Header.Level != syscall.IPPROTO_IP {
  87. continue
  88. }
  89. switch m.Header.Type {
  90. case syscall.IP_RECVTTL:
  91. cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
  92. case syscall.IP_RECVDSTADDR:
  93. v := m.Data[:4]
  94. cm.Dst = net.IPv4(v[0], v[1], v[2], v[3])
  95. case syscall.IP_RECVIF:
  96. sadl := (*syscall.SockaddrDatalink)(unsafe.Pointer(&m.Data[0]))
  97. cm.IfIndex = int(sadl.Index)
  98. }
  99. }
  100. return cm, nil
  101. }
  102. func marshalControlMessage(cm *ControlMessage) []byte {
  103. // TODO(mikio): Implement IP_PKTINFO stuff when OS X 10.8 comes
  104. return nil
  105. }