You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.2 KiB

  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. package ipv4
  5. import (
  6. "fmt"
  7. "net"
  8. "sync"
  9. "golang.org/x/net/internal/iana"
  10. "golang.org/x/net/internal/socket"
  11. )
  12. type rawOpt struct {
  13. sync.RWMutex
  14. cflags ControlFlags
  15. }
  16. func (c *rawOpt) set(f ControlFlags) { c.cflags |= f }
  17. func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f }
  18. func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
  19. type ControlFlags uint
  20. const (
  21. FlagTTL ControlFlags = 1 << iota // pass the TTL on the received packet
  22. FlagSrc // pass the source address on the received packet
  23. FlagDst // pass the destination address on the received packet
  24. FlagInterface // pass the interface index on the received packet
  25. )
  26. // A ControlMessage represents per packet basis IP-level socket options.
  27. type ControlMessage struct {
  28. // Receiving socket options: SetControlMessage allows to
  29. // receive the options from the protocol stack using ReadFrom
  30. // method of PacketConn or RawConn.
  31. //
  32. // Specifying socket options: ControlMessage for WriteTo
  33. // method of PacketConn or RawConn allows to send the options
  34. // to the protocol stack.
  35. //
  36. TTL int // time-to-live, receiving only
  37. Src net.IP // source address, specifying only
  38. Dst net.IP // destination address, receiving only
  39. IfIndex int // interface index, must be 1 <= value when specifying
  40. }
  41. func (cm *ControlMessage) String() string {
  42. if cm == nil {
  43. return "<nil>"
  44. }
  45. return fmt.Sprintf("ttl=%d src=%v dst=%v ifindex=%d", cm.TTL, cm.Src, cm.Dst, cm.IfIndex)
  46. }
  47. // Marshal returns the binary encoding of cm.
  48. func (cm *ControlMessage) Marshal() []byte {
  49. if cm == nil {
  50. return nil
  51. }
  52. var m socket.ControlMessage
  53. if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To4() != nil || cm.IfIndex > 0) {
  54. m = socket.NewControlMessage([]int{ctlOpts[ctlPacketInfo].length})
  55. }
  56. if len(m) > 0 {
  57. ctlOpts[ctlPacketInfo].marshal(m, cm)
  58. }
  59. return m
  60. }
  61. // Parse parses b as a control message and stores the result in cm.
  62. func (cm *ControlMessage) Parse(b []byte) error {
  63. ms, err := socket.ControlMessage(b).Parse()
  64. if err != nil {
  65. return err
  66. }
  67. for _, m := range ms {
  68. lvl, typ, l, err := m.ParseHeader()
  69. if err != nil {
  70. return err
  71. }
  72. if lvl != iana.ProtocolIP {
  73. continue
  74. }
  75. switch {
  76. case typ == ctlOpts[ctlTTL].name && l >= ctlOpts[ctlTTL].length:
  77. ctlOpts[ctlTTL].parse(cm, m.Data(l))
  78. case typ == ctlOpts[ctlDst].name && l >= ctlOpts[ctlDst].length:
  79. ctlOpts[ctlDst].parse(cm, m.Data(l))
  80. case typ == ctlOpts[ctlInterface].name && l >= ctlOpts[ctlInterface].length:
  81. ctlOpts[ctlInterface].parse(cm, m.Data(l))
  82. case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
  83. ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
  84. }
  85. }
  86. return nil
  87. }
  88. // NewControlMessage returns a new control message.
  89. //
  90. // The returned message is large enough for options specified by cf.
  91. func NewControlMessage(cf ControlFlags) []byte {
  92. opt := rawOpt{cflags: cf}
  93. var l int
  94. if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 {
  95. l += socket.ControlMessageSpace(ctlOpts[ctlTTL].length)
  96. }
  97. if ctlOpts[ctlPacketInfo].name > 0 {
  98. if opt.isset(FlagSrc | FlagDst | FlagInterface) {
  99. l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
  100. }
  101. } else {
  102. if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 {
  103. l += socket.ControlMessageSpace(ctlOpts[ctlDst].length)
  104. }
  105. if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 {
  106. l += socket.ControlMessageSpace(ctlOpts[ctlInterface].length)
  107. }
  108. }
  109. var b []byte
  110. if l > 0 {
  111. b = make([]byte, l)
  112. }
  113. return b
  114. }
  115. // Ancillary data socket options
  116. const (
  117. ctlTTL = iota // header field
  118. ctlSrc // header field
  119. ctlDst // header field
  120. ctlInterface // inbound or outbound interface
  121. ctlPacketInfo // inbound or outbound packet path
  122. ctlMax
  123. )
  124. // A ctlOpt represents a binding for ancillary data socket option.
  125. type ctlOpt struct {
  126. name int // option name, must be equal or greater than 1
  127. length int // option length
  128. marshal func([]byte, *ControlMessage) []byte
  129. parse func(*ControlMessage, []byte)
  130. }