control_unix.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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 linux netbsd openbsd
  5. package ipv4
  6. import (
  7. "os"
  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 newControlMessage(opt *rawOpt) (oob []byte) {
  60. opt.RLock()
  61. var l int
  62. if opt.isset(FlagTTL) {
  63. l += syscall.CmsgSpace(ctlOpts[ctlTTL].length)
  64. }
  65. if ctlOpts[ctlPacketInfo].name > 0 {
  66. if opt.isset(FlagSrc | FlagDst | FlagInterface) {
  67. l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
  68. }
  69. } else {
  70. if opt.isset(FlagDst) {
  71. l += syscall.CmsgSpace(ctlOpts[ctlDst].length)
  72. }
  73. if opt.isset(FlagInterface) {
  74. l += syscall.CmsgSpace(ctlOpts[ctlInterface].length)
  75. }
  76. }
  77. if l > 0 {
  78. oob = make([]byte, l)
  79. b := oob
  80. if opt.isset(FlagTTL) {
  81. b = ctlOpts[ctlTTL].marshal(b, nil)
  82. }
  83. if ctlOpts[ctlPacketInfo].name > 0 {
  84. if opt.isset(FlagSrc | FlagDst | FlagInterface) {
  85. b = ctlOpts[ctlPacketInfo].marshal(b, nil)
  86. }
  87. } else {
  88. if opt.isset(FlagDst) {
  89. b = ctlOpts[ctlDst].marshal(b, nil)
  90. }
  91. if opt.isset(FlagInterface) {
  92. b = ctlOpts[ctlInterface].marshal(b, nil)
  93. }
  94. }
  95. }
  96. opt.RUnlock()
  97. return
  98. }
  99. func parseControlMessage(b []byte) (*ControlMessage, error) {
  100. if len(b) == 0 {
  101. return nil, nil
  102. }
  103. cmsgs, err := syscall.ParseSocketControlMessage(b)
  104. if err != nil {
  105. return nil, os.NewSyscallError("parse socket control message", err)
  106. }
  107. cm := &ControlMessage{}
  108. for _, m := range cmsgs {
  109. if m.Header.Level != ianaProtocolIP {
  110. continue
  111. }
  112. switch int(m.Header.Type) {
  113. case ctlOpts[ctlTTL].name:
  114. ctlOpts[ctlTTL].parse(cm, m.Data[:])
  115. case ctlOpts[ctlDst].name:
  116. ctlOpts[ctlDst].parse(cm, m.Data[:])
  117. case ctlOpts[ctlInterface].name:
  118. ctlOpts[ctlInterface].parse(cm, m.Data[:])
  119. case ctlOpts[ctlPacketInfo].name:
  120. ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
  121. }
  122. }
  123. return cm, nil
  124. }
  125. func marshalControlMessage(cm *ControlMessage) (oob []byte) {
  126. if cm == nil {
  127. return nil
  128. }
  129. var l int
  130. if ctlOpts[ctlPacketInfo].name > 0 {
  131. if cm.Src.To4() != nil || cm.IfIndex != 0 {
  132. l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
  133. }
  134. }
  135. if l > 0 {
  136. oob = make([]byte, l)
  137. b := oob
  138. if ctlOpts[ctlPacketInfo].name > 0 {
  139. if cm.Src.To4() != nil || cm.IfIndex != 0 {
  140. b = ctlOpts[ctlPacketInfo].marshal(b, cm)
  141. }
  142. }
  143. }
  144. return
  145. }
  146. func marshalTTL(b []byte, cm *ControlMessage) []byte {
  147. m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
  148. m.Level = ianaProtocolIP
  149. m.Type = sysIP_RECVTTL
  150. m.SetLen(syscall.CmsgLen(1))
  151. return b[syscall.CmsgSpace(1):]
  152. }
  153. func parseTTL(cm *ControlMessage, b []byte) {
  154. cm.TTL = int(*(*byte)(unsafe.Pointer(&b[:1][0])))
  155. }